39

I am writing yaml file like this

with open(fname, "w") as f:
     yaml.safe_dump({'allow':'', 'deny': ''}, f,
                    default_flow_style=False, width=50, indent=4)

This outputs:

allow: ''

I want to output as

allow:

How can I do that?

Anthon
  • 69,918
  • 32
  • 186
  • 246
user3214546
  • 6,523
  • 13
  • 51
  • 98
  • you basically want to set it as null instead of an empty string? – DrCord May 08 '15 at 23:26
  • You're asking how to save a different value than the actual data? Why? If the actual data is an empty string, so should be the yaml representation of that data, shouldn't it? Have you tried setting the original values to `None`? – Bryan Oakley May 08 '15 at 23:30
  • @BryanOakley , if i put None , then it display null in yaml . i want to keep it blank. i am hard coding value . i was looking for variable which i can use in actual value to give blank output like null , None etc. i didn't want to use replace – user3214546 May 08 '15 at 23:34
  • 2
    In YAML a blank value is interpreted as null, so whats the differance? Just use `None`. It will get interpreted the same way. Unless, of course, there is some very specific reason you need it to be blank regardless of how it is interpreted. In which case you might want to let us know so we can help with that. Perhaps knowing the context of your request, someone could suggest a different way to get what you want. – Waylan May 09 '15 at 00:54
  • @Waylan IN all yaml files i have seen for config , the if key is usually empty then is blank not `(null or None or '')` so i just want to create file like that so that if i want to write something then i don't need to delete those un required characters – user3214546 May 09 '15 at 02:23
  • use `allow: null` In python, `allow: ''` need not work properly all the time. As per python __ZEN__ : "Explicit is always better than implicit" – Koo Apr 10 '19 at 17:17

4 Answers4

82

For None type to be read from python use null in yaml

A YAML file test.yml like this

foo: null
bar: null

will be read by python as

import yaml
test = yaml.load(open('./test.yml'))
print(test)

foo: None
bar: None
Koo
  • 1,442
  • 13
  • 16
16
from yaml import SafeDumper
import yaml

data = {'deny': None, 'allow': None}

SafeDumper.add_representer(
    type(None),
    lambda dumper, value: dumper.represent_scalar(u'tag:yaml.org,2002:null', '')
  )

with open('./yadayada.yaml', 'w') as output:
  yaml.safe_dump(data, output, default_flow_style=False)

There is a way to do this built into python yaml itself. The above code will produce a file containing:

allow:
deny:
Hans Nelsen
  • 297
  • 2
  • 4
12

If you load a YAML src

allow:

into Python you get None assigned to the key allow, that is the correct behaviour.

If you use ruamel.yaml (of which I am the author), and its RoundTripDumper, None is written as you want it (which is IMO the most readable, although not explicit):

import ruamel.yaml

print ruamel.yaml.dump(dict(allow=None), Dumper=ruamel.yaml.RoundTripDumper)

will give you:

allow:

You can also properly round-trip this:

import ruamel.yaml

yaml_src = """
allow:
key2: Hello  # some test

"""

data = ruamel.yaml.load(yaml_src, ruamel.yaml.RoundTripLoader)
print('#### 1')
print(data['allow'])
print('#### 2')
print(ruamel.yaml.dump(data, Dumper=ruamel.yaml.RoundTripDumper))

print('#### 3')

print(type(data))

to get as output:

#### 1
None
#### 2
allow:
key2: Hello  # some test


#### 3
<class 'ruamel.yaml.comments.CommentedMap'>

In the above, data is a subclass of ordereddict, which is necessary to keep track of the flowstyle of the input, handling comments attached to lines, order of the keys, etc..
Such a subclass can be created on the fly, but it is normally easier to start with some readable and well formatted YAML code (possible already saved on disc) and then update/extend the values.

Samuel Harmer
  • 4,264
  • 5
  • 33
  • 67
Anthon
  • 69,918
  • 32
  • 186
  • 246
5

Using replace, this seems straightforward:

import yaml

fname = 'test.yaml'
with open(fname, "w") as f:
    yaml_str = yaml.safe_dump({'allow':'', 'deny': ''},
                            default_flow_style=False,
                            width=50, 
                            indent=4).replace(r"''", '')
    f.write(yaml_str)

Is there a reason why you want to avoid replace?

There is the drawback that re-loading the yaml file does not reproduce your input:

>>> print yaml.safe_load(open(fname))
{'deny': None, 'allow': None}
sjdenny
  • 793
  • 1
  • 6
  • 11