From 693173e6c05bcfc7ae2e28eae749ce438974c9b4 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Mon, 22 Oct 2018 09:54:17 -0400 Subject: [PATCH 1/2] Add test to reproduce bug for missing schema... This tests the case where a tag is found from a known, available extension, but the specific type can't be found. Currently this results in an error, but ASDF should be able to load files even in this case, albeit with a warning. --- asdf/tests/test_schema.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/asdf/tests/test_schema.py b/asdf/tests/test_schema.py index 57cb7a8a5..63c292f4e 100644 --- a/asdf/tests/test_schema.py +++ b/asdf/tests/test_schema.py @@ -730,3 +730,39 @@ 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 asdf.open(buff) as af: + assert af['a'] == 'hello' + + + # This is a more realistic case since we're using an external extension + yaml = """ +a: ! + hello + """ + + buff = helpers.yaml_to_asdf(yaml) + with asdf.open(buff, extensions=CustomExtension()) as af: + assert af['a'] == 'hello' From 59afeffcdad85beef4105c622338448c01660bb4 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Mon, 22 Oct 2018 13:20:49 -0400 Subject: [PATCH 2/2] Fix bug with tree creation when schema file is missing --- CHANGES.rst | 4 ++++ asdf/schema.py | 8 +++++++- asdf/tests/test_schema.py | 21 ++++++++++++++++----- 3 files changed, 27 insertions(+), 6 deletions(-) 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 63c292f4e..0aa03b0d2 100644 --- a/asdf/tests/test_schema.py +++ b/asdf/tests/test_schema.py @@ -753,9 +753,15 @@ def test_nonexistent_tag(tmpdir): """ buff = helpers.yaml_to_asdf(yaml) - with asdf.open(buff) as af: - assert af['a'] == 'hello' - + 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 = """ @@ -764,5 +770,10 @@ def test_nonexistent_tag(tmpdir): """ buff = helpers.yaml_to_asdf(yaml) - with asdf.open(buff, extensions=CustomExtension()) as af: - assert af['a'] == 'hello' + 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)