read parse instalar create python yaml pyyaml

python - parse - ¿Cómo puedo controlar qué forma escalar utiliza PyYAML para mis datos?



python pyyaml (4)

¿ Está basado en las bibliotecas yaml de Python que admiten el volcado de cadenas largas como bloques literales o bloques plegados?

import yaml from collections import OrderedDict class quoted(str): pass def quoted_presenter(dumper, data): return dumper.represent_scalar(''tag:yaml.org,2002:str'', data, style=''"'') yaml.add_representer(quoted, quoted_presenter) class literal(str): pass def literal_presenter(dumper, data): return dumper.represent_scalar(''tag:yaml.org,2002:str'', data, style=''|'') yaml.add_representer(literal, literal_presenter) def ordered_dict_presenter(dumper, data): return dumper.represent_dict(data.items()) yaml.add_representer(OrderedDict, ordered_dict_presenter) d = OrderedDict(short=quoted("Hello"), long=literal("Line1/nLine2/nLine3/n")) print(yaml.dump(d))

Salida

short: "Hello" long: | Line1 Line2 Line3

Tengo un objeto con un atributo de cadena corta y un atributo de cadena multilínea larga. Quiero escribir la cadena corta como un escalar YAML entre comillas, y la cadena multilínea como un escalar literal:

my_obj.short = "Hello" my_obj.long = "Line1/nLine2/nLine3"

Me gustaría que el YAML se vea así:

short: "Hello" long: | Line1 Line2 Line3

¿Cómo puedo ordenar a PyYAML que haga esto? Si llamo a yaml.dump(my_obj) , produce una salida similar a un dict:

{long: ''line1 line2 line3 '', short: Hello}

(No estoy seguro de por qué el tiempo es doble espacio así ...)

¿Puedo dictar a PyYAML cómo tratar mis atributos? Me gustaría afectar tanto el orden como el estilo.


Al enamorarme del enfoque de @lbt , obtuve este código:

import yaml def str_presenter(dumper, data): if len(data.splitlines()) > 1: # check for multiline string return dumper.represent_scalar(''tag:yaml.org,2002:str'', data, style=''|'') return dumper.represent_scalar(''tag:yaml.org,2002:str'', data) yaml.add_representer(str, str_presenter)

Hace que cada cadena multilínea sea un bloque literal.

Estaba tratando de evitar la parte de parches de mono. Crédito completo para @lbt y @JFSebastian.


Puede usar ruamel.yaml y su RoundTripLoader / Dumper (descargo de responsabilidad: soy el autor de ese paquete) además de hacer lo que quiere, es compatible con la especificación YAML 1.2 (desde 2009) y tiene otras mejoras:

import sys from ruamel.yaml import YAML yaml_str = """/ short: "Hello" # does keep the quotes, but need to tell the loader long: | Line1 Line2 Line3 folded: > some like explicit folding of scalars for readability """ yaml = YAML() yaml.preserve_quotes = True data = yaml.load(yaml_str) yaml.dump(data, sys.stdout)

da:

short: "Hello" # does keep the quotes, but need to tell the loader long: | Line1 Line2 Line3 folded: > some like explicit folding of scalars for readability

(incluyendo el comentario, comenzando en la misma columna que antes)

También puede crear esta salida desde cero, pero luego debe proporcionar la información adicional, por ejemplo, las posiciones explícitas sobre dónde plegarse.


Quería que cualquier entrada con un /n en ella fuera un literal de bloque. Usando el código en yaml/representer.py como base obtuve:

# -*- coding: utf-8 -*- import yaml def should_use_block(value): for c in u"/u000a/u000d/u001c/u001d/u001e/u0085/u2028/u2029": if c in value: return True return False def my_represent_scalar(self, tag, value, style=None): if style is None: if should_use_block(value): style=''|'' else: style = self.default_style node = yaml.representer.ScalarNode(tag, value, style=style) if self.alias_key is not None: self.represented_objects[self.alias_key] = node return node a={''short'': "Hello", ''multiline'': """Line1 Line2 Line3 """, ''multiline-unicode'': u"""Lêne1 Lêne2 Lêne3 """} print(yaml.dump(a)) print(yaml.dump(a, allow_unicode=True)) yaml.representer.BaseRepresenter.represent_scalar = my_represent_scalar print(yaml.dump(a)) print(yaml.dump(a, allow_unicode=True))

Salida

{multiline: ''Line1 Line2 Line3 '', multiline-unicode: "L/xEAne1/nL/xEAne2/nL/xEAne3/n", short: Hello} {multiline: ''Line1 Line2 Line3 '', multiline-unicode: ''Lêne1 Lêne2 Lêne3 '', short: Hello} After override multiline: | Line1 Line2 Line3 multiline-unicode: "L/xEAne1/nL/xEAne2/nL/xEAne3/n" short: Hello multiline: | Line1 Line2 Line3 multiline-unicode: | Lêne1 Lêne2 Lêne3 short: Hello