diff --git a/CHANGES.rst b/CHANGES.rst index c4abc8707..eabf76e3a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -22,6 +22,10 @@ - Fix bug that occurred when attempting to open invalid file but Astropy import fails while checking for ASDF-in-FITS. [#562] +- Fix bug that caused tree creation to fail when unable to locate a schema file + for an unknown tag. This now simply causes a warning, and the offending node + is converted to basic Python data structures. [#571] + 2.1.0 (2018-09-25) ------------------ diff --git a/asdf/schema.py b/asdf/schema.py index 699bb5ce8..d7ac26378 100644 --- a/asdf/schema.py +++ b/asdf/schema.py @@ -4,6 +4,7 @@ import os import json import datetime +import warnings from numbers import Integral from functools import lru_cache from collections import OrderedDict @@ -218,7 +219,12 @@ def iter_errors(self, instance, _schema=None, _seen=set()): if tag is not None: schema_path = self.ctx.resolver(tag) if schema_path != tag: - s = load_schema(schema_path, self.ctx.resolver) + try: + s = load_schema(schema_path, self.ctx.resolver) + except FileNotFoundError: + msg = "Unable to locate schema file for '{}': '{}'" + warnings.warn(msg.format(tag, schema_path)) + s = {} if s: with self.resolver.in_scope(schema_path): for x in super(ASDFValidator, self).iter_errors(instance, s): diff --git a/asdf/tests/test_schema.py b/asdf/tests/test_schema.py index 57cb7a8a5..0aa03b0d2 100644 --- a/asdf/tests/test_schema.py +++ b/asdf/tests/test_schema.py @@ -730,3 +730,50 @@ def test_custom_validation_with_definitions_bad(tmpdir): with pytest.raises(ValidationError): with asdf.open(asdf_file, custom_schema=custom_schema_path) as ff: pass + + +def test_nonexistent_tag(tmpdir): + """ + This tests the case where a node is tagged with a type that apparently + comes from an extension that is known, but the type itself can't be found. + + This could occur when a more recent version of an installed package + provides the new type, but an older version of the package is installed. + ASDF should still be able to open the file in this case, but it won't be + able to restore the type. + + The bug that prompted this test results from attempting to load a schema + file that doesn't exist, which is why this test belongs in this file. + """ + + # This shouldn't ever happen, but it's a useful test case + yaml = """ +a: !core/doesnt_exist-1.0.0 + hello + """ + + buff = helpers.yaml_to_asdf(yaml) + with pytest.warns(None) as w: + with asdf.open(buff) as af: + assert str(af['a']) == 'hello' + # Currently there are 3 warnings since one occurs on each of the + # validation passes. It would be good to consolidate these eventually + assert len(w) == 3, helpers.display_warnings(w) + assert str(w[0].message).startswith("Unable to locate schema file") + assert str(w[1].message).startswith("Unable to locate schema file") + assert str(w[2].message).startswith(af['a']._tag) + + # This is a more realistic case since we're using an external extension + yaml = """ +a: ! + hello + """ + + buff = helpers.yaml_to_asdf(yaml) + with pytest.warns(None) as w: + with asdf.open(buff, extensions=CustomExtension()) as af: + assert str(af['a']) == 'hello' + assert len(w) == 3, helpers.display_warnings(w) + assert str(w[0].message).startswith("Unable to locate schema file") + assert str(w[1].message).startswith("Unable to locate schema file") + assert str(w[2].message).startswith(af['a']._tag)