First, a disclaimer: I'm not too familiar with YAML. I'm trying to parse a YAML doc into Key Value Pairs (don't worry about how I'm doing it. I've got that bit handled)
My file used to look something like:
world:
people:
name:Suzy
address:chez-bob
Then, someone went and changed it.
world:
people:
name:!$uzy
address:chez-bob
And I get this parse error:
yaml.constructor.ConstructorError: could not determine a constructor for the tag '!$uzy'
What does this even mean? How would I go about getting it to just interpret !$ as just two characters?
I just want a dictionary of string keys and values!
Also, editing the yaml files is not an option. Problem must be fixed in the code using the parser.
Exclamation mark is a prefix for YAML tags. The parser has to implement a constructor for it by the tag name. There are some default tags like !!bool
, !!int
, etc. and even some Python specific tags like !!python/tuple
.
You can define your own constructors and even constructors for multiple tags caught by a prefix. By defining the prefix to ''
, you can catch all the tags and ignore them. You can return the tag and its value from the constructor to just treat it all as text.
>>> import yaml
>>> def default_ctor(loader, tag_suffix, node):
... print loader
... print tag_suffix
... print node
... return tag_suffix + ' ' + node.value
...
>>> yaml.add_multi_constructor('', default_ctor)
>>> yaml.load(y)
<yaml.loader.Loader object at 0xb76ce8ec>
!$uzy
ScalarNode(tag=u'!$uzy', value=u'')
{'world': {'people': {'name': '!$uzy', 'address': 'chez-bob'}}}
>>>
If a value starts with "!", you must enclose the value in single or double quotes; otherwise it is interpreted as a YAML tag.
world:
people:
name: "!$uzy"
address: chez-bob
This is actually a bug in PyYAML. It interprets the :
in name:!$uzy
as a key/value separator, but it should only do so if :
is followed by a space, or if the preceding scalar (name
) is quoted. The follow up error is that the exclamation mark, which should be allowed in the middle of a scalar, gets incorrectly interpreted as being at the beginning of a scalar and hence introducing a tag.
The value for key people
is the string name:!$uzy address:chez-bob
and that is handled correctly in other parsers (including the Python package ruamel.yaml
of which I am the author).