Je sais qu'il y a quelques questions à ce sujet sur SO, mais je n'ai pas trouvé ce que je cherchais.
J'utilise pyyaml pour lire (.load()
) un fichier .yml
, Modifier ou ajouter une clé, puis l'écrire (.dump()
) encore. Le problème est que je souhaite conserver le format de fichier après le vidage, mais il change.
Par exemple, j'édite la clé en.test.index.few
Pour dire "Bye"
Au lieu de "Hello"
Python:
with open(path, 'r', encoding = "utf-8") as yaml_file:
self.dict = pyyaml.load(yaml_file)
Ensuite, après avoir changé la clé:
with open(path, 'w', encoding = "utf-8") as yaml_file:
dump = pyyaml.dump(self.dict, default_flow_style = False, allow_unicode = True, encoding = None)
yaml_file.write( dump )
Yaml:
Avant:
en:
test:
new: "Bye"
index:
few: "Hello"
anothertest: "Something"
Après:
en:
anothertest: Something
test:
index:
few: Hello
new: Bye
Existe-t-il un moyen de conserver le même format?, Par exemple les qoutes et l'ordre. Suis-je en train d'utiliser le mauvais outil pour cela?
Je sais que le fichier d'origine n'est peut-être pas tout à fait correct, mais je n'ai aucun contrôle sur lui (c'est un Ruby on Rails i18n file).
Merci beaucoup.
Utilisez plutôt ruamel.yaml
PyYAML est effectivement mort et l'est depuis plusieurs années. Pour aggraver les choses, la maison officielle du projet à http://pyyaml.org semble avoir été supprimée récemment. Ce site a hébergé le traqueur de problèmes PyYAML, la documentation et les téléchargements. Au moment de la rédaction de cet article, tous sont partis. Ce n'est rien de moins que calamiteux. Bienvenue à juste un autre jour en open-source.
ruamel.yaml
Est activement mainten . Contrairement à PyYAML, ruamel.yaml
Prend en charge:
yaml.dump()
pour vider un dictionnaire chargé par un appel précédent à yaml.load()
: ruamel.yaml
Respecte intelligemment tous le formatage d'entrée. Tout. Toute l'enchilada stylistique. Le Shebang littéraire entier. Tous. Étant donné que ruamel.yaml
Est une fourchette PyYAML et est donc conforme à l'API PyYAML, le passage de PyYAML à ruamel.yaml
Dans les applications existantes est généralement aussi simple que de remplacer toutes les instances de ceci:
# This imports PyYAML. Stop doing this.
import yaml
...avec ça:
# This imports "ruamel.yaml". Always do this.
from ruamel import yaml
C'est tout.
Aucun autre changement ne devrait être nécessaire. Les fonctions yaml.load()
et yaml.dump()
devraient continuer à se comporter comme prévu - avec les avantages supplémentaires de prendre désormais en charge YAML 1.2 et de recevoir activement des corrections de bogues.
Pour une compatibilité descendante avec PyYaml, les fonctions yaml.load()
et yaml.dump()
font pas effectuent la conservation aller-retour par défaut. Pour ce faire, passez explicitement:
Loader=ruamel.yaml.RoundTripLoader
Sur yaml.load()
.Dumper=ruamel.yaml.RoundTripDumper
Sur yaml.dump()
.Un exemple gentiment "emprunté" à la documentation ruamel.yaml
:
import ruamel.yaml
inp = """\
# example
name:
# Yet another Great Duke of Hell. He's not so bad, really.
family: TheMighty
given: Ashtaroth
"""
code = ruamel.yaml.load(inp, Loader=ruamel.yaml.RoundTripLoader)
code['name']['given'] = 'Astarte' # Oh no you didn't.
print(ruamel.yaml.dump(code, Dumper=ruamel.yaml.RoundTripDumper), end='')
C'est fait. Les commentaires, la commande, les citations et les espaces blancs seront maintenant conservés intacts.
Utilisez toujours ruamel.yaml
. N'utilisez jamais PyYAML. ruamel.yaml
Vit. PyYAML est un cadavre fétide pourrissant dans le sol de charnier de moulage de PyPi.
Vive ruamel.yaml
.
Premier
Pour représenter les données du dictionnaire est utilisé le code suivant:
mapping = list(mapping.items())
try:
mapping = sorted(mapping)
except TypeError:
pass
C'est pourquoi la commande est modifiée
Deuxième
Les informations sur la présentation du type scalaire (avec guillemets doubles ou non) sont perdues lors de la lecture (c'est l'approche principale de la bibliothèque)
Résumé
Vous pouvez créer votre propre classe basée sur 'Dumper' et surcharger la méthode 'represent_mapping' pour changer le comportement de présentation du dictionnaire
Pour enregistrer des informations sur les guillemets doubles pour scalaire, vous devez également créer votre propre classe basée sur "Loader", mais je crains que cela n'affecte et d'autres classes et qu'il soit difficile de le faire
Dans mon cas, je veux "
Si la valeur contient un {
Ou un }
, Sinon rien. Par exemple:
en:
key1: value is 1
key2: 'value is {1}'
Pour cela, copiez la fonction represent_str()
du fichier representer.py dans le module PyYaml et utilisez un autre style si la chaîne contient {
Ou un }
:
def represent_str(self, data):
tag = None
style = None
# Add these two lines:
if '{' in data or '}' in data:
style = '"'
try:
data = unicode(data, 'ascii')
tag = u'tag:yaml.org,2002:str'
except UnicodeDecodeError:
try:
data = unicode(data, 'utf-8')
tag = u'tag:yaml.org,2002:str'
except UnicodeDecodeError:
data = data.encode('base64')
tag = u'tag:yaml.org,2002:binary'
style = '|'
return self.represent_scalar(tag, data, style=style)
Pour l'utiliser dans votre code:
import yaml
def represent_str(self, data):
...
yaml.add_representer(str, represent_str)
Dans ce cas, aucune différence entre les clés et les valeurs et cela me suffit. Si vous voulez un style différent pour les clés et les valeurs, effectuez la même chose avec la fonction represent_mapping