read parse create python yaml pyyaml

python - parse - pyyaml install



¿Puede PyYAML volcar elementos de orden en orden no alfabético? (7)

Esto es realmente solo un addendum a la respuesta de @Blender. Si busca en la fuente PyYAML , en el módulo representer.py , encontrará este método:

def represent_mapping(self, tag, mapping, flow_style=None): value = [] node = MappingNode(tag, value, flow_style=flow_style) if self.alias_key is not None: self.represented_objects[self.alias_key] = node best_style = True if hasattr(mapping, ''items''): mapping = mapping.items() mapping.sort() for item_key, item_value in mapping: node_key = self.represent_data(item_key) node_value = self.represent_data(item_value) if not (isinstance(node_key, ScalarNode) and not node_key.style): best_style = False if not (isinstance(node_value, ScalarNode) and not node_value.style): best_style = False value.append((node_key, node_value)) if flow_style is None: if self.default_flow_style is not None: node.flow_style = self.default_flow_style else: node.flow_style = best_style return node

Si simplemente elimina la línea mapping.sort() , entonces mantiene el orden de los elementos en el OrderedDict .

Otra solución se da en este post . Es similar a @ Blender''s, pero funciona para safe_dump . El elemento común es la conversión del dict a una lista de tuplas, por lo que la if hasattr(mapping, ''items'') evalúa como falsa.

Actualizar:

Acabo de python2-yamlordereddictloader cuenta de que el repositorio de EPEL del Proyecto Fedora tiene un paquete llamado python2-yamlordereddictloader , y también hay uno para Python 3. El proyecto upstream para ese paquete es probablemente multiplataforma.

Estoy usando yaml.dump para generar un dict. Imprime cada elemento en orden alfabético según la clave.

>>> d = {"z":0,"y":0,"x":0} >>> yaml.dump( d, default_flow_style=False ) ''x: 0/ny: 0/nz: 0/n''

¿Hay alguna forma de controlar el orden de los pares clave / valor?

En mi caso de uso particular, imprimir en reversa sería (casualmente) lo suficientemente bueno. Sin embargo, para completar, estoy buscando una respuesta que muestre cómo controlar el orden de manera más precisa.

He analizado el uso de collections.OrderedDict pero PyYAML no (parece que) lo admite. También he buscado subclasificar yaml.Dumper , pero no he podido averiguar si tiene la capacidad de cambiar el orden de los artículos.


Hay dos cosas que debes hacer para obtener esto como quieras:

  • necesitas usar algo más que un dict , porque no mantiene los artículos ordenados
  • Necesitas deshacer esa alternativa de la manera apropiada.

import sys import ruamel.yaml from ruamel.yaml.comments import CommentedMap d = CommentedMap() d[''z''] = 0 d[''y''] = 0 d[''x''] = 0 ruamel.yaml.round_trip_dump(d, sys.stdout)

salida:

z: 0 y: 0 x: 0

¹ Esto se hizo usando ruamel.yaml un analizador de YAML 1.2, del cual soy el autor.


Para Python 3.7+, los dictados conservan el orden de inserción. Es mejor usar una biblioteca que respete eso, como oyaml :

>>> import oyaml as yaml # pip install oyaml >>> d = {"z": 0, "y": 0, "x": 0} >>> yaml.dump(d, default_flow_style=False) ''z: 0/ny: 0/nx: 0/n''


Probablemente haya una solución mejor, pero no pude encontrar nada en la documentación ni en la fuente.

Python 2 (ver comentarios)

OrderedDict y le hice devolver una lista de elementos no almacenables:

from collections import OrderedDict class UnsortableList(list): def sort(self, *args, **kwargs): pass class UnsortableOrderedDict(OrderedDict): def items(self, *args, **kwargs): return UnsortableList(OrderedDict.items(self, *args, **kwargs)) yaml.add_representer(UnsortableOrderedDict, yaml.representer.SafeRepresenter.represent_dict)

Y parece funcionar:

>>> d = UnsortableOrderedDict([ ... (''z'', 0), ... (''y'', 0), ... (''x'', 0) ... ]) >>> yaml.dump(d, default_flow_style=False) ''z: 0/ny: 0/nx: 0/n''

Python 3 o 2 (ver comentarios)

También puede escribir un representante personalizado, pero no sé si se encontrará con problemas más adelante, ya que eliminé un código de verificación de estilo:

import yaml from collections import OrderedDict def represent_ordereddict(dumper, data): value = [] for item_key, item_value in data.items(): node_key = dumper.represent_data(item_key) node_value = dumper.represent_data(item_value) value.append((node_key, node_value)) return yaml.nodes.MappingNode(u''tag:yaml.org,2002:map'', value) yaml.add_representer(OrderedDict, represent_ordereddict)

Pero con eso, puedes usar la clase nativa OrderedDict .


Sobre la base de la respuesta de @orodbhen:

old_sorted = __builtins__[''sorted''] __builtins__[''sorted''] = lambda x: x with open(filename, ''w'') as outfile: yaml.dump(f_json, outfile) __builtins[''sorted''] = old_sorted

Simplemente reemplace la función incorporada ordenada por una función de identidad lambda mientras usa yaml.dump.


También estaba buscando una respuesta a la pregunta "¿cómo volcar asignaciones con el orden conservado?" No pude seguir la solución dada anteriormente, ya que soy nuevo en pyyaml ​​y python. Después de dedicar algo de tiempo a la documentación de pyyaml ​​y otros foros, encontré esto.

Puedes usar la etiqueta

!! omap

para volcar los mapeos conservando el orden. Si quieres jugar con el orden, creo que tienes que ir por las claves: valores

Los siguientes enlaces pueden ayudar a una mejor comprensión.

https://bitbucket.org/xi/pyyaml/issue/13/loading-and-then-dumping-an-omap-is-broken

http://yaml.org/type/omap.html


Una sola línea para gobernarlos a todos:

yaml.add_representer(dict, lambda self, data: yaml.representer.SafeRepresenter.represent_dict(self, data.items()))

Eso es. Finalmente. Después de todos esos años y horas, el poderoso represent_dict ha sido derrotado dándole el dict.items() lugar de solo dict

Así es como funciona:

Este es el código fuente de PyYaml relevante:

if hasattr(mapping, ''items''): mapping = list(mapping.items()) try: mapping = sorted(mapping) except TypeError: pass for item_key, item_value in mapping:

Para evitar la clasificación, solo necesitamos un objeto Iterable[Pair] .items() que no tenga .items() .

dict_items es un candidato perfecto para esto.

Aquí es cómo hacer esto sin afectar el estado global del módulo yaml:

#Using a custom Dumper class to prevent changing the global state class CustomDumper(yaml.Dumper): #Super neat hack to preserve the mapping key order. See https://.com/a/52621703/1497385 def represent_dict_preserve_order(self, data): return self.represent_dict(data.items()) CustomDumper.add_representer(dict, CustomDumper.represent_dict_preserve_order) return yaml.dump(component_dict, Dumper=CustomDumper)