7

I am loading a yaml True/False item(example below) from a YAML file.

gzip: False

This is correctly interpreted in a Jinja2 template as boolean True.

The same YAML file is being read by another script, passed over as a python CGI form data and eventually written to the YAML file using

with open(myyaml, 'w') as yaml_file:
    yaml_file.write(yaml.dump(dict, default_flow_style=False)) 

The issue is that this then writes the True/False with a single quote

gzip: 'False'

which causes the jinja2 template to not interpret the value as boolean and always sets value as true in

{{ if gzip }}

Is there a way to dump the YAML file with True/False values that are treated as boolean ( I mean without the quotes ).

Anthon
  • 69,918
  • 32
  • 186
  • 246
Anoop P Alias
  • 373
  • 1
  • 6
  • 15
  • Of course it will not automatically parse a string `'False'` as boolean. That’s not special to neither Jinja2 nor to YAML. That’s the same thing everywhere. How should it know that you want to parse the value? You will have to do that explicitly if your data is not stored properly in the YAML file. – poke Nov 03 '16 at 07:17
  • 2
    The problem is that the quotes are added by yaml.dump . Initially when I create the yaml it does not have quotes ,or the question can be rephrased as How can I dump a value to yaml explicitly specifying it as boolean and not string . I think the form.get is converting the True/False to string . – Anoop P Alias Nov 03 '16 at 07:22
  • `yaml.dump` will *not* dump a boolean as a string if it was an actual boolean before: `yaml.dump({ 'Foo': 'Bar', 'Baz': True })` gives you `'{Baz: true, Foo: Bar}\n'` – No quotes. YAML is designed to be mostly quoteless anyway. – poke Nov 03 '16 at 07:29

1 Answers1

4

.dump() just dumps the data that it gets and it must have gotten a string instead of boolean as value for the key gzip. Since that string value, if dumped unquoted can be misinterpreted as a boolean it gets quoted.

Since you get your material from a CGI form any value True or False will be a string. Before dumping your data, you explicitly have to convert these values you got from CGI to booleans.

You can walk over your dictionary and do something generic processing before you dump:

import sys
import yaml

# simulating getting string type values from CGI
data = dict(gzip='False', intval="1", strval="abc") 

for k in data:
    v = data[k]
    try:
        v = int(v)
        data[k] = v
    except ValueError:
        vl = v.lower()
        if vl == 'false':
            data[k] = False
        elif vl == 'true':
            data[k] = True

yaml.safe_dump(data, sys.stdout, default_flow_style=False)

gives:

gzip: false
intval: 1
strval: abc

Please note that abc is not quoted, because it cannot be interpreted as anything else but a string. The above of course also converts strings 'True' or 'False' that would have to stay strings. If that is not what you want, you have to select conversion based on the key.

There are two other major problems with your two lines of Python:

with open(myyaml, 'w') as yaml_file:
    yaml_file.write(yaml.dump(dict, default_flow_style=False)) 
  1. You should never use a Python keyword (dict) as a variable name, that is just asking for trouble later on in your code.
  2. yaml.dump() dumps data to a stream. It has a facility that if you don't specify the stream where things have to go to, the output is written to an internal stream object, from which the final value is returned. You should not abuse this, to then write this returned value to the yaml_file. Instead do:

    with open(myyaml, 'w') as yaml_file:
        yaml.dump(dict, yaml_file, default_flow_style=False))
    

    Your way is inefficient (apart from showing lack of understanding).

Anthon
  • 69,918
  • 32
  • 186
  • 246
  • The dict keyword was not used..i just want to quickly say a dictionary was used in the code . Thanks for pointing out the problem with my yaml.dump style. I will accept your answer as the form was indeed getting the string value instead of boolean. – Anoop P Alias Nov 03 '16 at 07:43
  • @AnoopPAlias Sorry for misinterpreting `dict`. I can recommend using something like `my_dict` in such cases. You will always see that the next visitor here will cut and paste your code, and it will work, until the keyword needs to be used for its real purpose (of course by someone else maintaining the code a few years onwards) :-). – Anthon Nov 03 '16 at 07:59