Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bugfix: yaml default mapping value resolver breaks parsing of simple string lists #775

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions lib/yaml/constructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
'ConstructorError'
]

from collections import defaultdict
from .error import *
from .nodes import *

Expand Down Expand Up @@ -134,13 +135,16 @@ def construct_mapping(self, node, deep=False):
raise ConstructorError(None, None,
"expected a mapping node, but found %s" % node.id,
node.start_mark)
mapping = {}
mapping = defaultdict()
for key_node, value_node in node.value:
key = self.construct_object(key_node, deep=deep)
if not isinstance(key, collections.abc.Hashable):
raise ConstructorError("while constructing a mapping", node.start_mark,
"found unhashable key", key_node.start_mark)
value = self.construct_object(value_node, deep=deep)

if key_node.tag == "tag:yaml.org,2002:value":
mapping.default_factory = self.mapping_values_default_factory(value)
mapping[key] = value
return mapping

Expand Down Expand Up @@ -168,13 +172,13 @@ def add_multi_constructor(cls, tag_prefix, multi_constructor):
cls.yaml_multi_constructors = cls.yaml_multi_constructors.copy()
cls.yaml_multi_constructors[tag_prefix] = multi_constructor

@staticmethod
def mapping_values_default_factory(value):
return lambda: value

class SafeConstructor(BaseConstructor):

def construct_scalar(self, node):
if isinstance(node, MappingNode):
for key_node, value_node in node.value:
if key_node.tag == 'tag:yaml.org,2002:value':
return self.construct_scalar(value_node)
return super().construct_scalar(node)

def flatten_mapping(self, node):
Expand Down Expand Up @@ -204,9 +208,6 @@ def flatten_mapping(self, node):
raise ConstructorError("while constructing a mapping", node.start_mark,
"expected a mapping or list of mappings for merging, but found %s"
% value_node.id, value_node.start_mark)
elif key_node.tag == 'tag:yaml.org,2002:value':
key_node.tag = 'tag:yaml.org,2002:str'
index += 1
else:
index += 1
if merge:
Expand Down Expand Up @@ -408,10 +409,11 @@ def construct_yaml_seq(self, node):
data.extend(self.construct_sequence(node))

def construct_yaml_map(self, node):
data = {}
data = defaultdict()
yield data
value = self.construct_mapping(node)
data.update(value)
data.default_factory = value.default_factory

def construct_yaml_object(self, node, cls):
data = cls.__new__(cls)
Expand Down Expand Up @@ -468,6 +470,10 @@ def construct_undefined(self, node):
'tag:yaml.org,2002:str',
SafeConstructor.construct_yaml_str)

SafeConstructor.add_constructor(
'tag:yaml.org,2002:value',
SafeConstructor.construct_yaml_str)

SafeConstructor.add_constructor(
'tag:yaml.org,2002:seq',
SafeConstructor.construct_yaml_seq)
Expand Down Expand Up @@ -670,6 +676,10 @@ def construct_python_object_new(self, suffix, node):
'tag:yaml.org,2002:python/str',
FullConstructor.construct_python_str)

FullConstructor.add_constructor(
'tag:yaml.org,2002:python/value',
FullConstructor.construct_python_str)

FullConstructor.add_constructor(
'tag:yaml.org,2002:python/unicode',
FullConstructor.construct_python_unicode)
Expand Down
1 change: 1 addition & 0 deletions tests/legacy_tests/data/str.data
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
- abcd
- =