2

In my yam file I am trying this

with open(fname, "w") as f:
     yaml.safe_dump({'items':['test', 'test2']}, f,
                    default_flow_style=False, width=50, indent=4)

It prints in the below format

items:
- 'test'
- 'test2'

I want the output formatted like below

items: ['test', 'test2']

How can I do that ?

EDIT:

This is my complete code

   d = {}        
   for m in ['B1', 'B2', 'B3']:
                d2 = {}
                for f in ['A1', 'A2', 'A3']:
                    # here i don't want any flow style
                    d2[f] = ['test', 'test2']
                d[m] = d2

    with open(fname, "w") as f:
        yaml.safe_dump(d, f, default_flow_style=True, width=50, indent=8)
famousgarkin
  • 13,687
  • 5
  • 58
  • 74
user3214546
  • 6,523
  • 13
  • 51
  • 98
  • 2
    Why did you add `default_flow_style=False` if you want the default flow style? – abarnert May 11 '15 at 04:42
  • 1
    @abarnert i have nested dict , i don't want default flow style for only one dict but for other i want. is it possible – user3214546 May 11 '15 at 04:46
  • possible duplicate of [Specifying styles for portions of a PyYAML dump](http://stackoverflow.com/questions/14000893/specifying-styles-for-portions-of-a-pyyaml-dump) – famousgarkin May 11 '15 at 05:32
  • Do you want all list in your YAML file to be flow style, or only specific lists? – Anthon May 11 '15 at 06:08

2 Answers2

2

Don't put the default_flow_style=False then, does the complete opposite of what you want:

>>> import yaml
>>> yaml.safe_dump({'items': ['test', 'test2']}, default_flow_style=False)
'items:\n- test\n- test2\n'
>>> yaml.safe_dump({'items': ['test', 'test2']})
'items: [test, test2]\n'

As for partial document formatting, you can do with custom representers, e.g.:

class Items(list):
    pass


def items_representer(dumper, data):
    return dumper.represent_sequence('tag:yaml.org,2002:seq', data, flow_style=True)


yaml.representer.SafeRepresenter.add_representer(Items, items_representer)

result = yaml.safe_dump({
    'items': Items(['test', 'test2']),
    'other list': ['1', '2'],
}, default_flow_style=False)

# items: [test, test2]
# other list:
# - '1'
# - '2'
print(result)
famousgarkin
  • 13,687
  • 5
  • 58
  • 74
2

If you want fine control and only have specific lists with flow style, you should use ruamel.yaml (which is my enhanced version of PyYAML):

import ruamel.yaml
from ruamel.yaml.comments import CommentedSeq

d = {}
for m in ['B1', 'B2', 'B3']:
    d2 = {}
    for f in ['A1', 'A2', 'A3']:
        # here i don't want any flow style
        d2[f] = CommentedSeq(['test', 'test2'])
        if f != 'A2':
            d2[f].fa.set_flow_style()
    d[m] = d2

x = ruamel.yaml.dump(
    d, Dumper=ruamel.yaml.RoundTripDumper,
    default_flow_style=False, width=50, indent=8)
print(x)

will give you:

B1:
        A1: [test, test2]
        A3: [test, test2]
        A2:
        - test
        - test2
B2:
        A1: [test, test2]
        A3: [test, test2]
        A2:
        - test
        - test2
B3:
        A1: [test, test2]
        A3: [test, test2]
        A2:
        - test
        - test2

The CommentedSeq behaves just like a normal Python list, but allows you to specify comment, set flow/block style etc.

ruamel.yaml is normally used to preserve comments, flow/block style on elements, etc., when round-tripping YAML. I.e. if you would append:

d2 = ruamel.yaml.load(x, Loader=ruamel.yaml.RoundTripLoader)
y = ruamel.yaml.dump(
    d2, Dumper=ruamel.yaml.RoundTripDumper, width=50, indent=8)
assert x == y

the assertion holds.

But it can of course be used to genenerate YAML from scratch as well. You could e.g. also use the CommentedMap type and keep the keys of your dict/mapping ordered.

Anthon
  • 69,918
  • 32
  • 186
  • 246
  • @user3214546 provide a `stream=fp` to `dump()` with fp an open file pointer (`with open('somefile.yaml', 'w') as fp:`). If `stream` is `None` the "dump" is returned as a string. – Anthon May 11 '15 at 10:04
  • i am using your library . Is there any way i can add comment at the top of file , like describing what the purpose of file is rather with keys – user3214546 Jun 23 '15 at 01:21
  • @user3214546 Yes there is, as those start of file comments are preserved if you round-trip. Each comment is a line of its own so it is never just replacing one line. Can you post a new question, clearly stating what you start with (file with comment at top that need changing (if so how many lines), file without a comment at the top), what needs to be inserted (one comment line, multiple comment lines). Ping me here if you do and I will answer as soon as I can. – Anthon Jun 23 '15 at 04:59
  • I have added the question here http://stackoverflow.com/questions/30994370/how-can-i-add-comment-in-yaml-file-in-python – user3214546 Jun 23 '15 at 05:17
  • if i use `CommentedSeq(["test"])` then the output is `[test]` how can i get the output as `['test']` – user3214546 Jun 26 '15 at 03:36
  • @user3214546 Do you want control over individual scalar elements? Do all sequence nodes have to be quoted? Or only the sequence nodes with `CommentedSeq()`? Or only withing `CommentedSeq()` when they have value "test"? Or only if there is one element? For all string scalars in the document (including keys), you can use `dump(default_style='"'). *You should update your post with the complete example of what you get + what you want to get to prevent further ambiguities* (and un-accept the answer if that doesn't solve your problem) – Anthon Jun 26 '15 at 05:01