training - ¿Alguna biblioteca de yaml en Python que admita el volcado de cadenas largas como bloques literales o bloques plegados?
yaml tutorial español (3)
Me gustaría poder volcar un diccionario que contenga cadenas largas que me gustaría tener en el estilo de bloque para facilitar la lectura. Por ejemplo:
foo: |
this is a
block literal
bar: >
this is a
folded block
PyYAML admite la carga de documentos con este estilo pero parece que no puedo encontrar una manera de volcar documentos de esta manera. ¿Me estoy perdiendo de algo?
Esto se puede hacer con relativa facilidad, ya que el único "obstáculo" es cómo indicar cuál de los espacios de la cadena, que debe representarse como un escalar plegado, debe convertirse en un pliegue. El escalar literal tiene nuevas líneas explícitas que contienen esa información, pero esto no se puede usar para escalas plegadas, ya que pueden contener nuevas líneas explícitas, por ejemplo, en caso de que haya espacios en blanco iniciales y también se necesite una nueva línea al final para no ser representados con un chumping de extracción. indicador ( >-
)
import sys
import ruamel.yaml
folded = ruamel.yaml.scalarstring.FoldedScalarString
literal = ruamel.yaml.scalarstring.LiteralScalarString
yaml = ruamel.yaml.YAML()
data = dict(
foo=literal(''this is a/nblock literal/n''),
bar=folded(''this is a folded block/n''),
)
data[''bar''].fold_pos = [data[''bar''].index('' folded'')]
yaml.dump(data, sys.stdout)
lo que da:
foo: |
this is a
block literal
bar: >
this is a
folded block
El atributo fold_pos
espera un iterable reversible, que representa las posiciones de los espacios que indican dónde plegarse.
Si nunca tiene caracteres de canalización (''|'') en sus cadenas, podría haber hecho algo como:
import re
s = ''this is a|folded block/n''
sf = folded(s.replace(''|'', '' '')) # need to have a space!
sf.fold_pos = [x.start() for x in re.finditer(''/|'', s)] # | is special in re, needs escaping
data = dict(
foo=literal(''this is a/nblock literal/n''),
bar=sf, # need to have a space
)
yaml = ruamel.yaml.YAML()
yaml.dump(data, sys.stdout)
lo que también da exactamente la salida que esperas
pyyaml
admite el volcado de bloques literales o plegados.
Usando Representer.add_representer
tipos de definición:
class folded_str(str): pass
class literal_str(str): pass
class folded_unicode(unicode): pass
class literal_unicode(str): pass
Luego puedes definir los representantes para esos tipos. Tenga en cuenta que si bien la solution funciona a la perfección con Unicode, es posible que necesite un poco más de trabajo para que las cadenas funcionen correctamente (consulte la implementación de represent_str ).
def change_style(style, representer):
def new_representer(dumper, data):
scalar = representer(dumper, data)
scalar.style = style
return scalar
return new_representer
import yaml
from yaml.representer import SafeRepresenter
# represent_str does handle some corner cases, so use that
# instead of calling represent_scalar directly
represent_folded_str = change_style(''>'', SafeRepresenter.represent_str)
represent_literal_str = change_style(''|'', SafeRepresenter.represent_str)
represent_folded_unicode = change_style(''>'', SafeRepresenter.represent_unicode)
represent_literal_unicode = change_style(''|'', SafeRepresenter.represent_unicode)
Luego, puede agregar esos representantes al dumper predeterminado:
yaml.add_representer(folded_str, represent_folded_str)
yaml.add_representer(literal_str, represent_literal_str)
yaml.add_representer(folded_unicode, represent_folded_unicode)
yaml.add_representer(literal_unicode, represent_literal_unicode)
... y probarlo:
data = {
''foo'': literal_str(''this is a/nblock literal''),
''bar'': folded_unicode(''this is a folded block''),
}
print yaml.dump(data)
resultado:
bar: >-
this is a folded block
foo: |-
this is a
block literal
Utilizando default_style
Si está interesado en que todas sus cadenas sigan un estilo predeterminado, también puede usar el argumento de palabra clave default_style
, por ejemplo:
>>> data = { ''foo'': ''line1/nline2/nline3'' }
>>> print yaml.dump(data, default_style=''|'')
"foo": |-
line1
line2
line3
o para literales plegados:
>>> print yaml.dump(data, default_style=''>'')
"foo": >-
line1
line2
line3
o para literales entre comillas dobles:
>>> print yaml.dump(data, default_style=''"'')
"foo": "line1/nline2/nline3"
Advertencias:
Aquí hay un ejemplo de algo que no puedes esperar:
data = {
''foo'': literal_str(''this is a/nblock literal''),
''bar'': folded_unicode(''this is a folded block''),
''non-printable'': literal_unicode(''this has a /t tab in it''),
''leading'': literal_unicode('' with leading white spaces''),
''trailing'': literal_unicode(''with trailing white spaces ''),
}
print yaml.dump(data)
resultados en:
bar: >-
this is a folded block
foo: |-
this is a
block literal
leading: |2-
with leading white spaces
non-printable: "this has a /t tab in it"
trailing: "with trailing white spaces "
1) caracteres no imprimibles
Consulte la especificación de YAML para los caracteres escapados ( Sección 5.7 ):
Tenga en cuenta que las secuencias de escape solo se interpretan en escalares de comillas dobles. En todos los demás estilos escalares, el carácter "/" no tiene un significado especial y los caracteres no imprimibles no están disponibles.
Si desea conservar caracteres no imprimibles (p. Ej., TAB), debe usar scalars entre comillas dobles. Si puede volcar un escalar con un estilo literal, y hay un carácter no imprimible (por ejemplo, TAB) allí, su dumper YAML no es compatible.
Por ejemplo, pyyaml
detecta el carácter no imprimible /t
y utiliza el estilo entre comillas dobles aunque se especifique un estilo predeterminado:
>>> data = { ''foo'': ''line1/nline2/n/tline3'' }
>>> print yaml.dump(data, default_style=''"'')
"foo": "line1/nline2/n/tline3"
>>> print yaml.dump(data, default_style=''>'')
"foo": "line1/nline2/n/tline3"
>>> print yaml.dump(data, default_style=''|'')
"foo": "line1/nline2/n/tline3"
2) espacios en blanco iniciales y finales
Otro bit de información útil en la especificación es:
Todos los caracteres de espacio en blanco iniciales y finales se excluyen del contenido
Esto significa que si su cadena tiene espacios en blanco al principio o al final, estos no se conservarán en estilos escalares distintos de los que figuran entre comillas dobles. Como consecuencia, pyyaml
intenta detectar lo que está en su escalar y puede forzar el estilo de doble cita.
import yaml
class folded_unicode(unicode): pass
class literal_unicode(unicode): pass
def folded_unicode_representer(dumper, data):
return dumper.represent_scalar(u''tag:yaml.org,2002:str'', data, style=''>'')
def literal_unicode_representer(dumper, data):
return dumper.represent_scalar(u''tag:yaml.org,2002:str'', data, style=''|'')
yaml.add_representer(folded_unicode, folded_unicode_representer)
yaml.add_representer(literal_unicode, literal_unicode_representer)
data = {
''literal'':literal_unicode(
u''by hjw ___/n''
'' __ /.-.///n''
'' / )_____________//// Y/n''
'' /_ /=== == === === =// _//_/n''
''( /)=== == === === == Y ///n''
'' `-------------------( o )/n''
'' //___//n''),
''folded'': folded_unicode(
u''It removes all ordinary curses from all equipped items. ''
''Heavy or permanent curses are unaffected./n'')}
print yaml.dump(data)
El resultado:
folded: >
It removes all ordinary curses from all equipped items. Heavy or permanent curses
are unaffected.
literal: |
by hjw ___
__ /.-./
/ )_____________// Y
/_ /=== == === === =/ _/_
( /)=== == === === == Y /
`-------------------( o )
/___/
Para completar, uno también debe tener implementaciones de str, pero voy a ser perezoso :-)