def test_extension_version_warning(): yaml = """ history: extensions: - !core/extension_metadata-1.0.0 extension_class: asdf.extension.BuiltinExtension software: !core/software-1.0.0 name: asdf version: 100.0.3 """ buff = yaml_to_asdf(yaml) with pytest.warns( AsdfWarning, match= "File was created with extension class 'asdf.extension.BuiltinExtension'" ): with asdf.open(buff): pass buff.seek(0) # Make sure suppressing the warning works too with assert_no_warnings(): with asdf.open(buff, ignore_missing_extensions=True): pass
def test_assert_roundtrip_with_extension(tmpdir): called_custom_assert_equal = [False] class CustomType(dict, types.CustomType): name = 'custom_flow' organization = 'nowhere.org' version = (1, 0, 0) standard = 'custom' @classmethod def assert_equal(cls, old, new): called_custom_assert_equal[0] = True class CustomTypeExtension(CustomExtension): @property def types(self): return [CustomType] tree = {'custom': CustomType({'a': 42, 'b': 43})} def check(ff): assert isinstance(ff.tree['custom'], CustomType) with helpers.assert_no_warnings(): helpers.assert_roundtrip_tree(tree, tmpdir, extensions=[CustomTypeExtension()]) assert called_custom_assert_equal[0] is True
def test_metadata_with_custom_extension(tmpdir): class FractionType(types.CustomType): name = 'fraction' organization = 'nowhere.org' version = (1, 0, 0) standard = 'custom' types = [fractions.Fraction] @classmethod def to_tree(cls, node, ctx): return [node.numerator, node.denominator] @classmethod def from_tree(cls, tree, ctx): return fractions.Fraction(tree[0], tree[1]) class FractionExtension(CustomExtension): @property def types(self): return [FractionType] tree = {'fraction': fractions.Fraction(2, 3)} tmpfile = str(tmpdir.join('custom_extension.asdf')) with asdf.AsdfFile(tree, extensions=FractionExtension()) as ff: ff.write_to(tmpfile) # We expect metadata about both the Builtin extension and the custom one with asdf.open(tmpfile, extensions=FractionExtension()) as af: assert len(af['history']['extensions']) == 2 with pytest.warns(AsdfWarning, match="was created with extension"): with asdf.open(tmpfile, ignore_unrecognized_tag=True): pass # If we use the extension but we don't serialize any types that require it, # no metadata about this extension should be added to the file tree2 = {'x': [x for x in range(10)]} tmpfile2 = str(tmpdir.join('no_extension.asdf')) with asdf.AsdfFile(tree2, extensions=FractionExtension()) as ff: ff.write_to(tmpfile2) with asdf.open(tmpfile2) as af: assert len(af['history']['extensions']) == 1 with assert_no_warnings(): with asdf.open(tmpfile2): pass # Make sure that this works even when constructing the tree on-the-fly tmpfile3 = str(tmpdir.join('custom_extension2.asdf')) with asdf.AsdfFile(extensions=FractionExtension()) as ff: ff.tree['fraction'] = fractions.Fraction(4, 5) ff.write_to(tmpfile3) with asdf.open(tmpfile3, extensions=FractionExtension()) as af: assert len(af['history']['extensions']) == 2
def test_mapping_supported_key_types(keys, version): for key in keys: with helpers.assert_no_warnings(): af = asdf.AsdfFile({key: "value"}, version=version) buff = io.BytesIO() af.write_to(buff) buff.seek(0) with asdf.open(buff) as af: assert af[key] == "value"
def test_asdf_file_version_requirement(): extension_with_requirement = TestExtension( extension_uri="asdf://somewhere.org/extensions/foo-1.0", asdf_standard_requirement="==1.5.0", ) # No warnings if the requirement is fulfilled: with assert_no_warnings(): AsdfFile(version="1.5.0", extensions=[extension_with_requirement]) # Version doesn't match the requirement, so we should see a warning # and the extension should not be enabled: with pytest.warns(AsdfWarning, match="does not support ASDF Standard 1.4.0"): af = AsdfFile(version="1.4.0", extensions=[extension_with_requirement]) assert ExtensionProxy(extension_with_requirement) not in af.extensions # Version initially matches the requirement, but changing # the version on the AsdfFile invalidates it: af = AsdfFile(version="1.5.0", extensions=[extension_with_requirement]) assert ExtensionProxy(extension_with_requirement) in af.extensions with pytest.warns(AsdfWarning, match="does not support ASDF Standard 1.4.0"): af.version = "1.4.0" assert ExtensionProxy(extension_with_requirement) not in af.extensions # Extension registered with the config should not provoke # a warning: with config_context() as config: config.add_extension(extension_with_requirement) with assert_no_warnings(): af = AsdfFile(version="1.4.0") assert ExtensionProxy( extension_with_requirement) not in af.extensions # ... unless the user explicitly requested the invalid exception: with pytest.warns(AsdfWarning, match="does not support ASDF Standard 1.4.0"): af = AsdfFile(version="1.4.0", extensions=[extension_with_requirement])
def test_reading_extension_metadata(): extension_with_uri = ExtensionProxy( TestExtension(extension_uri="asdf://somewhere.org/extensions/foo-1.0"), package_name="foo", package_version="1.2.3", ) extension_without_uri = ExtensionProxy( TestExtension(), package_name="foo", package_version="1.2.3", ) extension_with_legacy_class_names = ExtensionProxy( TestExtension( extension_uri="asdf://somewhere.org/extensions/with-legacy-1.0", legacy_class_names={"some.legacy.class.Name"}, ), package_name="foo", package_version="1.2.3", ) with config_context() as config: config.add_extension(extension_with_uri) config.add_extension(extension_without_uri) config.add_extension(extension_with_legacy_class_names) # Test missing history: content = """ foo: bar """ buff = yaml_to_asdf(content) with assert_no_warnings(): open_asdf(buff) # Test the old history format: content = """ history: - !core/history_entry-1.0.0 description: Once upon a time, there was a carnivorous panda. - !core/history_entry-1.0.0 description: This entry intentionally left blank. foo: bar """ buff = yaml_to_asdf(content, standard_version="1.0.0") with assert_no_warnings(): open_asdf(buff) # Test legacy extension matching by actual class name: content = """ history: extensions: - !core/extension_metadata-1.0.0 extension_class: asdf.tests.test_asdf.TestExtension """ buff = yaml_to_asdf(content) with assert_no_warnings(): open_asdf(buff) # Test matching by URI: content = """ history: extensions: - !core/extension_metadata-1.0.0 extension_uri: asdf://somewhere.org/extensions/foo-1.0 extension_class: some.unrecognized.extension.class.Name """ buff = yaml_to_asdf(content) with assert_no_warnings(): open_asdf(buff) # Test matching by legacy class name: content = """ history: extensions: - !core/extension_metadata-1.0.0 extension_class: some.legacy.class.Name """ buff = yaml_to_asdf(content) with assert_no_warnings(): open_asdf(buff) # Warn when the URI is missing, even if there's # a class name match: content = """ history: extensions: - !core/extension_metadata-1.0.0 extension_uri: some-missing-URI extension_class: {} """.format(extension_with_uri.class_name) buff = yaml_to_asdf(content) with pytest.warns(AsdfWarning, match="URI 'some-missing-URI'"): open_asdf(buff) # Warn when the class name is missing: content = """ history: extensions: - !core/extension_metadata-1.0.0 extension_class: some.missing.class.Name """ buff = yaml_to_asdf(content) with pytest.warns(AsdfWarning, match="class 'some.missing.class.Name'"): open_asdf(buff) # Warn when the package version is older: content = """ history: extensions: - !core/extension_metadata-1.0.0 extension_uri: asdf://somewhere.org/extensions/foo-1.0 extension_class: some.class.Name software: !core/software-1.0.0 name: foo version: 9.2.4 """ buff = yaml_to_asdf(content) with pytest.warns(AsdfWarning, match="older package"): open_asdf(buff) # Shouldn't warn when the package version is later: content = """ history: extensions: - !core/extension_metadata-1.0.0 extension_uri: asdf://somewhere.org/extensions/foo-1.0 extension_class: some.class.Name software: !core/software-1.0.0 name: foo version: 0.1.2 """ buff = yaml_to_asdf(content) with assert_no_warnings(): open_asdf(buff) # Shouldn't receive a warning when the package # name changes, even if the version is later: content = """ history: extensions: - !core/extension_metadata-1.0.0 extension_uri: asdf://somewhere.org/extensions/foo-1.0 extension_class: some.class.Name software: !core/software-1.0.0 name: bar version: 9.4.5 """ buff = yaml_to_asdf(content) with assert_no_warnings(): open_asdf(buff)