2017-10-13 6 views
0

Je cherche maintenant des jours, en essayant de découvrir pourquoi mon analyseur yaml (en utilisant PyYaml) ne sauvegarde pas le YAML, car il était à l'état original.Python yaml paquet analyse nouvelle ligne quand elle n'est pas nécessaire

La ligne originale en YAML est:

healthcheck: 
    test: ["CMD-SHELL", "[ x\"`curl -k --silent -w '%{http_code}' https://localhost:4433 | grep 401`\" = x\"\" ] && exit 1 || exit 0"]  
    interval: 30s 

Mais la nouvelle ligne (juste de charger le fichier et l'enregistrer à nouveau):

healthcheck: 
     interval: 30s 
     test: 
     - CMD-SHELL 
     - '[ x"`curl -k --silent -w ''%{http_code}'' https://localhost:4433 | grep 401`" 
     = x"" ] && exit 1 || exit 0' 

Il y a deux problèmes ici: 1) la valeur "test" devient une liste au lieu d'une paire de valeurs de clé de ligne. 2) il y a en fait 3 nouvelle ligne ici,

a) -CMD-SHELL 
b)- '[ x"`curl -k --silent -w ''%{http_code}'' https://localhost:4433 | grep 401`" 
c)= x"" ] && exit 1 || exit 0' 

pour que l'autre question est, pourquoi la troisième ligne a été brisée de la deuxième ligne? (Si je montre un espace blanc, vous verrez qu'à la fin de la deuxième ligne il a LF et commence alors la troisième ligne

Répondre

1

Je pense que vous pouvez avoir quelques malentendus sur la syntaxe YAML.Ce:

test: ["this", "is", "a", "list"] 

est exactement équivalent à ceci:

test: 
    - this 
    - is 
    - a 
    - list 

Et ceci:

- "This is a string value" 

est exactement équivalent à:

- "This is a 
    string value" 

Si je laisse tomber votre exemple en un fichier data.yml:

$ cat data.yml 
healthcheck: 
    test: ["CMD-SHELL", "[ x\"`curl -k --silent -w '%{http_code}' https://localhost:4433 | grep 401`\" = x\"\" ] && exit 1 || exit 0"] 
    interval: 30s 

Et puis analyser avec PyYAML:

>>> import yaml 
>>> with open('data.yml') as fd: 
... data = yaml.load(fd) 
... 

-je obtenir la structure de données Python suivantes:

>>> pprint.pprint(data) 
{'healthcheck': {'interval': '30s', 
       'test': ['CMD-SHELL', 
          '[ x"`curl -k --silent -w \'%{http_code}\' https://localhost:4433 | grep 401`" = x"" ] && exit 1 || exit 0']}} 

Et si je Dump en utilisant PyYAML, je reçois:

>>> print yaml.dump(data) 
healthcheck: 
    interval: 30s 
    test: [CMD-SHELL, '[ x"`curl -k --silent -w ''%{http_code}'' https://localhost:4433 
     | grep 401`" = x"" ] && exit 1 || exit 0'] 

... ce qui semble très bien. Je peux demander la syntaxe de la liste plus détaillée, dans ce cas, je reçois ce que vous montrez dans votre exemple:

>>> print yaml.dump(data, default_flow_style=False) 
healthcheck: 
    interval: 30s 
    test: 
    - CMD-SHELL 
    - '[ x"`curl -k --silent -w ''%{http_code}'' https://localhost:4433 | grep 401`" 
    = x"" ] && exit 1 || exit 0' 

... qui analysera exactement la même structure de données Python que le document original. A part "look different", les données réelles sont identiques.

0

PyYAML n'est pas très bon à préserver style sur l'aller-retour (chargement, modifier, coffre-fort), il ne peut en fait pas conserver votre entrée telle quelle en utilisant ses paramètres de chargement/déchargement.Pour cela, vous devez modifier l'analyseur PyYAML

C'est ce qui est fait dans ruamel.yaml (avertissement: J'en suis l'auteur) paquet), qui a été spécialement développé pour soutenir ces allers-retours programmatiques (y compris la préservation des commentaires):

import sys 
import ruamel.yaml 
from pathlib import Path 

yaml_file = Path('test.yaml') 
out_file = Path('out.yaml') 

yaml = ruamel.yaml.YAML() 
yaml.width = 2048 
yaml.preserve_quotes = True 
data = yaml.load(yaml_file) 
yaml.dump(data, out_file) 

Ceci vous donne un out.yaml avec exactement le même contenu que test.yaml. La largeur par défaut (80) entoure votre ligne comme dans PyYAML, ce qui la place à quelque chose de plus long que votre ligne de longueur maximale. Le preserve_quotes est nécessaire car sinon les guillemets superflus dans "CMD-SHELL" seraient supprimés.

qui précède suppose Python 3 (pour pathlib), si vous exécutez encore Python 2, vous pouvez remettre une poignée de fichier normal correctement ouvert:

with open('test.yaml') as fp: 
    data = yaml.load(fp) 
with open('out.yaml', 'w') as fp: 
    yaml.dump(data, fp)