Can I control the formatting of multiline strings?
Asked Answered
O

1

9

The following code:

from ruamel.yaml import YAML
import sys, textwrap

yaml = YAML()
yaml.default_flow_style = False
yaml.dump({
    'hello.py': textwrap.dedent("""\
        import sys
        sys.stdout.write("hello world")
    """)
}, sys.stdout)

produces:

hello.py: "import sys\nsys.stdout.write(\"hello world\")\n"

is there a way to make it produce:

hello.py: |
    import sys
    sys.stdout.write("hello world")

instead?

Versions:

python: 2.7.16 on Win10 (1903)
ruamel.ordereddict==0.4.14
ruamel.yaml==0.16.0
ruamel.yaml.clib==0.1.0
Olia answered 6/8, 2019 at 19:9 Comment(0)
H
11

If you load, then dump, your expected output, you'll see that ruamel.yaml can actually preserve the block style literal scalar.

import sys
import ruamel.yaml

yaml_str = """\
hello.py: |
    import sys
    sys.stdout.write("hello world")
"""

yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)

as this gives again the loaded input:

hello.py: |
  import sys
  sys.stdout.write("hello world")

To find out how it does that you should inspect the type of your multi-line string:

print(type(data['hello.py']))

which prints:

<class 'ruamel.yaml.scalarstring.LiteralScalarString'>

and that should point you in the right direction:

from ruamel.yaml import YAML
from ruamel.yaml.scalarstring import LiteralScalarString
import sys, textwrap

def LS(s):
    return LiteralScalarString(textwrap.dedent(s))


yaml = ruamel.yaml.YAML()
yaml.dump({
    'hello.py': LS("""\
        import sys
        sys.stdout.write("hello world")
    """)
}, sys.stdout)

which also outputs what you want:

hello.py: |
  import sys
  sys.stdout.write("hello world")
Halloo answered 6/8, 2019 at 20:6 Comment(3)
Awesome, thanks! (github.com/datakortet/yamldirs/commit/…)Olia
Thank you for the answer. Is there a way to achieve this without needing to prefix all of your multi-line strings with the LS() function? This current solution means that you can't just dump a regular dict to yaml, but instead have the identity each multiline string and add the function before dumping.Quasi
@JoeJ There is a utility function walk_tree in scalarstring.py that does that for simple data structures recursively. But it is of course also possible to do that during dumping, although with less control.Halloo

© 2022 - 2024 — McMap. All rights reserved.