Search code examples
pythonyamlpyyaml

Reading YAML file with Python results in yaml.scanner.ScannerError: mapping values are not allowed here


I am using the following code:

import yaml
with open('/Users/edamame/my_logins/my_config.yaml', 'r') as infile:
    db_cfg = yaml.safe_load(infile)

which tries to read my_config.yaml:

database_info:
    username: edamame
    password: mypassword
    host: 1.2.3.4
    port: 3306
    database: mydb

but got the following error:

Traceback (most recent call last):
  File "/Users/edamame/my_project/extract_appointments.py", line 16, in <module>
    db_cfg = yaml.safe_load(infile)
  File "/Users/edamame/my_project/venv/lib/python3.6/site-packages/yaml/__init__.py", line 94, in safe_load
    return load(stream, SafeLoader)
  File "/Users/edamame/my_project/venv/lib/python3.6/site-packages/yaml/__init__.py", line 72, in load
    return loader.get_single_data()
  File "/Users/edamame/my_project/venv/lib/python3.6/site-packages/yaml/constructor.py", line 35, in get_single_data
    node = self.get_single_node()
  File "/Users/edamame/my_project/venv/lib/python3.6/site-packages/yaml/composer.py", line 36, in get_single_node
    document = self.compose_document()
  File "/Users/edamame/my_project/venv/lib/python3.6/site-packages/yaml/composer.py", line 55, in compose_document
    node = self.compose_node(None, None)
  File "/Users/edamame/my_project/venv/lib/python3.6/site-packages/yaml/composer.py", line 84, in compose_node
    node = self.compose_mapping_node(anchor)
  File "/Users/edamame/my_project/venv/lib/python3.6/site-packages/yaml/composer.py", line 127, in compose_mapping_node
    while not self.check_event(MappingEndEvent):
  File "/Users/edamame/my_project/venv/lib/python3.6/site-packages/yaml/parser.py", line 98, in check_event
    self.current_event = self.state()
  File "/Users/edamame/my_project/venv/lib/python3.6/site-packages/yaml/parser.py", line 428, in parse_block_mapping_key
    if self.check_token(KeyToken):
  File "/Users/edamame/my_project/venv/lib/python3.6/site-packages/yaml/scanner.py", line 116, in check_token
    self.fetch_more_tokens()
  File "/Users/edamame/my_project/venv/lib/python3.6/site-packages/yaml/scanner.py", line 220, in fetch_more_tokens
    return self.fetch_value()
  File "/Users/edamame/my_project/venv/lib/python3.6/site-packages/yaml/scanner.py", line 576, in fetch_value
    self.get_mark())
yaml.scanner.ScannerError: mapping values are not allowed here
  in "/Users/edamame/my_logins/my_config.yaml", line 5, column 9

Here are my installations: enter image description here Any idea what I missed here?


Solution

  • The input you show, doesn't generate that error. You can try that out here:

    You most likely have some whitespace difference, most likely in the port: 3306 line. Please note that because PyYAML pre-dates the latest YAML standard (1.2 from 2009) it still considers some Unicode whitespace characters whitespace, although the standard doesn't.

    If you cannot find what causes this by looking at the file, these are two possible options:

    • Try copy and pasting the file into an online parser a line at a time, until you see an error pop up. That gives you an clear indication what line is wrong.
    • Dump the datastructure that you need using a YAML dumper from data constructed in Python

    The latter cannot easily be done within PyYAML as it will sort the keys of a mapping on writing.

    import sys
    import ruamel.yaml
    from ruamel.yaml.comments import CommentedMap as cm
    
    data = cm()
    data['database_info'] = d = cm()
    d['username'] = 'edamame'
    d['password'] = 'mypassword'
    d['host'] = '1.2.3.4'
    d['port'] = 3306
    d['database'] = 'mydb'
    
    
    yaml = ruamel.yaml.YAML()
    yaml.indent(mapping=4)
    
    with open('my_config.yaml', 'w') as ofp:
        yaml.dump(data, ofp)
    

    which generates the following content in my_config.yaml:

    database_info:
        username: edamame
        password: mypassword
        host: 1.2.3.4
        port: 3306
        database: mydb
    

    A file which (even) PyYAML should be able to read.