How to make Python Yaml library save in a human-friendly way?

℡╲_俬逩灬. 提交于 2019-12-24 04:58:21

问题


Here is the Python code I've got:

d = {'ToGoFirst': 'aaa', 'Second': 'bbb', 'Pagargaph':
'''Lorem ipsum dolor sit amet, 
consectetur adipiscing elit, 
sed do eiusmod tempor incididunt 
ut labore et dolore magna aliqua.''',  
'Integer': 25}
with open('d.yaml', 'w') as f:
    yaml.safe_dump(d, f, default_flow_style=False)

What I keep getting:

Integer: 25
Pagargaph: "Lorem ipsum dolor sit amet, \nconsectetur adipiscing elit, \nsed do eiusmod\
  \ tempor incididunt \nut labore et dolore magna aliqua."
Second: bbb
ToGoFirst: aaa

How do I change it to produce:

ToGoFirst: aaa
Second: bbb
Pagargaph: 
  Lorem ipsum dolor sit amet, 
  consectetur adipiscing elit, 
  sed do eiusmod tempor incididunt 
  ut labore et dolore magna aliqua.
Integer: 25

In other words I want to:

  1. Avoid quotation marks and escape characters in the output so non-technical users can read and edit those config files.

  2. Ideally preserve the order of parameters.

This is to be able to load a YAML file, add more parameters and still be able to save it in a human-friendly format.


回答1:


Your output has no newlines in the value for Pagargaph, for that you would need to have a block-style literal scalar (the dash trims the final newline, you would normally get when loading such a scalar):

Pagargaph: |-
  Lorem ipsum dolor sit amet, 
  consectetur adipiscing elit, 
  sed do eiusmod tempor incididunt 
  ut labore et dolore magna aliqua.

You should use ruamel.yaml (disclaimer: I am the author of that package), which is specifically developed to support this kind of round-tripping. To get what you want do e.g.:

import sys
import ruamel.yaml
from ruamel.yaml.scalarstring import PreservedScalarString as L

yaml_str = """\
ToGoFirst: aaa
Second: 'bbb'  # insert after this one
Integer: 25
"""

yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
d = yaml.load(yaml_str)
# yaml.indent(mapping=4, sequence=4, offset=2)
try:
    before_integer = [k for k in d].index('Integer')
except ValueError:
    before_integer = len(d)
d.insert(before_integer, 'Pagargaph', L('''Lorem ipsum dolor sit amet, 
consectetur adipiscing elit, 
sed do eiusmod tempor incididunt 
ut labore et dolore magna aliqua.'''))  
d.insert(before_integer, 'Something', 'extra', comment='with a comment')
yaml.dump(d, sys.stdout)

resulting in:

ToGoFirst: aaa
Second: 'bbb'  # insert after this one
Something: extra # with a comment
Pagargaph: |-
  Lorem ipsum dolor sit amet, 
  consectetur adipiscing elit, 
  sed do eiusmod tempor incididunt 
  ut labore et dolore magna aliqua.
Integer: 25

Please note:

  • the order is preserved in any version of Python supported by ruamel.yaml (2.7, 3.4+)
  • the comment is preserved
  • the quotes that I added around bbb are preserved only if you specify yaml.preserve_quotes = True
  • since we insert twice at position 2, the latter bumps the former to position 3.

Your users will have to be a bit disciplined for them to be able to edit a YAML file and not break it. They should also know some of the caveats, such as that plain (non-quoted) scalars, cannot start with some special characters or contain special character sequences (: followed by space, # preceded by space)

To help prevent your users from making editing mistakes, you can try to add the following comment at the beginning of the YAML document:

# please read the first few "rules" of How_to_edit at the bottom of this file

and at the end:

How_to_edit: |
 Editing a YAML document is easy, but there are some rules to keep you from 
 accidently invoking its hidden powers. Of the following you need at least 
 read and apply the ones up to the divider separating the important from less 
 important rules. The less important ones are interesting, but you probably 
 won't need to know them.
 1) Entries in this file consist of a scalar key (before the ':') and a scalar 
    value (normally after the ':', but read rule 3). 
 2) Scalars do NOT need quotes (single: ', or double: ") around them, unless 
    you have a special character or characters combinations at the beginning 
    ('%', '*', '&', '{', '[', '- ') or in the middle  (': ', ' #) of the  scalar.
    If you add quotes use a single quote before and after the scalar . If 
    these are superfluous the program can remove them. So when in doubt just 
    add them.
 3) A key followed by ': |' introduces a multiline scalar. These instructions
    are in a multiline scalar. Such a scalar starts on the next line after ': |'.
    The lines need to be indented, until the end of the scalar and these 
    indentation spaces are not part of the scalar. 
    The newlines in a multiline sclar are hard (i.e. preserved, and not 
    substituted with spaces).
    If you see `: |-` that means the scalar is loaded with the trailing newline 
    stripped.
 4) Anything after a space followed by a hash (' #') is a comment, when not 
    within quotes or in a multiline string.
 --- end of the important rules ---
 5) Within single quoted scalars you can have a single quote by doubling it: 
       rule 4: 'you probably don''t ever need that'
    This is called escaping the single quote. You can double quote scalars, but 
    the rules for escaping are much more difficult, so don't try that at home.
 6) The scalars consisting solely of "True" and "False" (also all-caps and 
    all-lowercase) are loaded as booleans when unquoted, and as strings when 
    quoted. 
 7) Scalars consisting solely of number characters (0-9) are loaded as numbers.
    If there is a non-number they are usually loaded as strings, but scalars 
    starting with '0x' and '0o' and for the rest have only number characters,
    are special and need quotes if not intended as (hexadecimal resp. octal) 
    numbers.

If you include the above, you probably don't want to preserve quotes when round-tripping.



来源:https://stackoverflow.com/questions/51187751/how-to-make-python-yaml-library-save-in-a-human-friendly-way

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!