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

add _IgnoreCustomTagsLoader and use it in load_yaml #1825

Merged
merged 3 commits into from
Aug 20, 2024
Merged
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
14 changes: 14 additions & 0 deletions asdf/_tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,17 @@ def test_load_yaml(tmp_path, input_type, tagged):
assert isinstance(tree["a"], asdf.tagged.TaggedDict)
else:
assert not isinstance(tree["a"], asdf.tagged.TaggedDict)


@pytest.mark.parametrize("tagged", [True, False])
def test_load_yaml_recursion(tmp_path, tagged):
fn = tmp_path / "test.asdf"
tree = {}
tree["d"] = {}
tree["d"]["d"] = tree["d"]
tree["l"] = []
tree["l"].append(tree["l"])
asdf.AsdfFile(tree).write_to(fn)
tree = util.load_yaml(fn, tagged=tagged)
assert tree["d"]["d"] is tree["d"]
assert tree["l"][0] is tree["l"]
4 changes: 2 additions & 2 deletions asdf/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,12 @@ def load_yaml(init, tagged=False):
"""

from .generic_io import get_file
from .yamlutil import AsdfLoader
from .yamlutil import AsdfLoader, _IgnoreCustomTagsLoader

if tagged:
loader = AsdfLoader
else:
loader = yaml.CBaseLoader if getattr(yaml, "__with_libyaml__", None) else yaml.BaseLoader
loader = _IgnoreCustomTagsLoader

with get_file(init, "r") as gf:
reader = gf.reader_until(
Expand Down
23 changes: 23 additions & 0 deletions asdf/yamlutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,29 @@
AsdfDumper.add_representer(np.bytes_, AsdfDumper.represent_binary)


class _IgnoreCustomTagsLoader(_yaml_base_loader):
"""
A specialized YAML loader that ignores tags unknown to the
base (safe) loader. This is used by `asdf.util.load_yaml`
to read the ASDF tree as "basic" objects, ignoring the
custom tags.
"""

def construct_undefined(self, node):
if isinstance(node, yaml.MappingNode):
return self.construct_mapping(node)
elif isinstance(node, yaml.SequenceNode):
return self.construct_sequence(node)
elif isinstance(node, yaml.ScalarNode):
return self.construct_scalar(node)
return super().construct_undefined(node)

Check warning on line 155 in asdf/yamlutil.py

View check run for this annotation

Codecov / codecov/patch

asdf/yamlutil.py#L151-L155

Added lines #L151 - L155 were not covered by tests


# pyyaml will invoke the constructor associated with None when a node's
# tag is not explicitly handled by another constructor.
_IgnoreCustomTagsLoader.add_constructor(None, _IgnoreCustomTagsLoader.construct_undefined)


class AsdfLoader(_yaml_base_loader):
"""
A specialized YAML loader that can construct "tagged basic Python
Expand Down
1 change: 1 addition & 0 deletions changes/1825.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allow ``asdf.util.load_yaml`` to handle recursive objects
Loading