def test_config_context_nested(): assert get_config().validate_on_read is True with asdf.config_context() as config1: config1.validate_on_read = False with asdf.config_context() as config2: config2.validate_on_read = True with asdf.config_context() as config3: config3.validate_on_read = False assert get_config().validate_on_read is False assert get_config().validate_on_read is True
def test_resource_manager(): with asdf.config_context() as config: # Initial resource manager should contain just the entry points resources: assert "http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager assert b"http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager[ "http://stsci.edu/schemas/asdf/core/asdf-1.1.0"] assert "http://somewhere.org/schemas/foo-1.0.0" not in config.resource_manager # Add a mapping and confirm that the manager now contains it: new_mapping = {"http://somewhere.org/schemas/foo-1.0.0": b"foo"} config.add_resource_mapping(new_mapping) assert "http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager assert b"http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager[ "http://stsci.edu/schemas/asdf/core/asdf-1.1.0"] assert "http://somewhere.org/schemas/foo-1.0.0" in config.resource_manager assert config.resource_manager[ "http://somewhere.org/schemas/foo-1.0.0"] == b"foo" # Remove a mapping and confirm that the manager no longer contains it: config.remove_resource_mapping(new_mapping) assert "http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager assert b"http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager[ "http://stsci.edu/schemas/asdf/core/asdf-1.1.0"] assert "http://somewhere.org/schemas/foo-1.0.0" not in config.resource_manager # Reset and confirm that the manager no longer contains the custom mapping: config.add_resource_mapping(new_mapping) config.reset_resources() assert "http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager assert b"http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager[ "http://stsci.edu/schemas/asdf/core/asdf-1.1.0"] assert "http://somewhere.org/schemas/foo-1.0.0" not in config.resource_manager
def test_extension_version_check(installed, extension, warns): proxy = ExtensionProxy(FooExtension(), package_name="foo", package_version=installed) with config_context() as config: config.add_extension(proxy) af = asdf.AsdfFile() af._fname = 'test.asdf' tree = { 'history': { 'extensions': [ asdf.tags.core.ExtensionMetadata( extension_class='asdf.tests.test_api.FooExtension', software=asdf.tags.core.Software(name='foo', version=extension)), ] } } if warns: with pytest.warns(AsdfWarning, match="File 'test.asdf' was created with"): af._check_extensions(tree) with pytest.raises(RuntimeError) as err: af._check_extensions(tree, strict=True) err.match("^File 'test.asdf' was created with") else: af._check_extensions(tree)
def test_validate_on_read(): with asdf.config_context() as config: assert config.validate_on_read == asdf.config.DEFAULT_VALIDATE_ON_READ config.validate_on_read = False assert get_config().validate_on_read is False config.validate_on_read = True assert get_config().validate_on_read is True
def test_table_inline(tmpdir): table = np.array([(0, 1, (2, 3)), (4, 5, (6, 7))], dtype=[(str('MINE'), np.int8), (str(''), np.float64), (str('arr'), '>i4', (2, ))]) tree = {'table_data': table} def check_raw_yaml(content): tree = yaml.safe_load(re.sub(br'!core/\S+', b'', content)) assert tree['table_data'] == { 'datatype': [{ 'datatype': 'int8', 'name': 'MINE' }, { 'datatype': 'float64', 'name': 'f1' }, { 'datatype': 'int32', 'name': 'arr', 'shape': [2] }], 'data': [[0, 1.0, [2, 3]], [4, 5.0, [6, 7]]], 'shape': [2] } with asdf.config_context() as config: config.array_inline_threshold = 100 helpers.assert_roundtrip_tree(tree, tmpdir, raw_yaml_check_func=check_raw_yaml)
def test_legacy_fill_schema_defaults(): with asdf.config_context() as config: assert config.legacy_fill_schema_defaults == asdf.config.DEFAULT_LEGACY_FILL_SCHEMA_DEFAULTS config.legacy_fill_schema_defaults = False assert get_config().legacy_fill_schema_defaults is False config.legacy_fill_schema_defaults = True assert get_config().legacy_fill_schema_defaults is True
def test_array_inline_threshold(): with asdf.config_context() as config: assert config.array_inline_threshold == asdf.config.DEFAULT_ARRAY_INLINE_THRESHOLD config.array_inline_threshold = 10 assert get_config().array_inline_threshold == 10 config.array_inline_threshold = None assert get_config().array_inline_threshold is None
def register_schemas(): schemas_root = Path(__file__).parent / "schemas" with asdf.config_context() as config: config.add_resource_mapping( asdf.resource.DirectoryResourceMapping( schemas_root, "http://example.com/schemas")) yield
def test_config_context(): assert get_config().validate_on_read is True with asdf.config_context() as config: config.validate_on_read = False assert get_config().validate_on_read is False assert get_config().validate_on_read is True
def test_default_version(): with asdf.config_context() as config: assert config.default_version == asdf.config.DEFAULT_DEFAULT_VERSION assert "1.2.0" != asdf.config.DEFAULT_DEFAULT_VERSION config.default_version = "1.2.0" assert config.default_version == "1.2.0" with pytest.raises(ValueError): config.default_version = "0.1.5"
def test_config_repr(): with asdf.config_context() as config: config.validate_on_read = True config.default_version = "1.5.0" config.legacy_fill_schema_defaults = False assert "validate_on_read: True" in repr(config) assert "default_version: 1.5.0" in repr(config) assert "legacy_fill_schema_defaults: False" in repr(config)
def _config_context(self, **kwargs): # Temporarily set (default) options in asdf.config_context. This is useful # during writing/updating data. if ("array_inline_threshold" not in kwargs or kwargs["array_inline_threshold"] is None): kwargs["array_inline_threshold"] = self._array_inline_threshold with config_context() as config: for k, v in kwargs.items(): setattr(config, k, v) yield
def test_array_inline_threshold_recursive(tmpdir): models = pytest.importorskip('astropy.modeling.models') aff = models.AffineTransformation2D(matrix=[[1, 2], [3, 4]]) tree = {'test': aff} def check_asdf(asdf): assert len(list(asdf.blocks.internal_blocks)) == 0 with asdf.config_context() as config: config.array_inline_threshold = 100 helpers.assert_roundtrip_tree(tree, tmpdir, asdf_check_func=check_asdf)
def test_global_config(): assert get_config().validate_on_read is True get_config().validate_on_read = False assert get_config().validate_on_read is False with asdf.config_context() as config: assert config.validate_on_read is False config.validate_on_read = True assert get_config().validate_on_read is True assert get_config().validate_on_read is False
def test_array_inline_threshold(array_inline_threshold, inline_blocks, internal_blocks, tmp_path): file_path = tmp_path / "test.asdf" tree = {"small_array": np.arange(6), "large_array": np.arange(100)} with asdf.config_context() as config: config.array_inline_threshold = array_inline_threshold with asdf.AsdfFile(tree) as af: af.write_to(file_path) assert len(list(af.blocks.inline_blocks)) == inline_blocks assert len(list(af.blocks.internal_blocks)) == internal_blocks
def test_tag_validator(): content = """%YAML 1.1 --- $schema: http://stsci.edu/schemas/asdf/asdf-schema-1.0.0 id: asdf://somewhere.org/schemas/foo tag: asdf://somewhere.org/tags/foo ... """ with asdf.config_context() as config: config.add_resource_mapping( {"asdf://somewhere.org/schemas/foo": content}) schema_tree = schema.load_schema("asdf://somewhere.org/schemas/foo") instance = tagged.TaggedDict(tag="asdf://somewhere.org/tags/foo") schema.validate(instance, schema=schema_tree) with pytest.raises(ValidationError): schema.validate( tagged.TaggedDict(tag="asdf://somewhere.org/tags/bar"), schema=schema_tree) content = """%YAML 1.1 --- $schema: http://stsci.edu/schemas/asdf/asdf-schema-1.0.0 id: asdf://somewhere.org/schemas/bar tag: asdf://somewhere.org/tags/bar-* ... """ with asdf.config_context() as config: config.add_resource_mapping( {"asdf://somewhere.org/schemas/bar": content}) schema_tree = schema.load_schema("asdf://somewhere.org/schemas/bar") instance = tagged.TaggedDict(tag="asdf://somewhere.org/tags/bar-2.5") schema.validate(instance, schema=schema_tree) with pytest.raises(ValidationError): schema.validate( tagged.TaggedDict(tag="asdf://somewhere.org/tags/foo-1.0"), schema=schema_tree)
def test_array_inline_threshold_string_array(array_inline_threshold, inline_blocks, internal_blocks, tmp_path): file_path = tmp_path / "test.asdf" arr = np.array( ["peach", "plum", "apricot", "nectarine", "cherry", "pluot"]) tree = {"array": arr} with asdf.config_context() as config: config.array_inline_threshold = array_inline_threshold with asdf.AsdfFile(tree) as af: af.write_to(file_path) assert len(list(af.blocks.inline_blocks)) == inline_blocks assert len(list(af.blocks.internal_blocks)) == internal_blocks
def test_array_inline_threshold_masked_array(array_inline_threshold, inline_blocks, internal_blocks, tmp_path): file_path = tmp_path / "test.asdf" arr = np.arange(6) masked_arr = np.ma.masked_equal(arr, 3) tree = {"masked_arr": masked_arr} with asdf.config_context() as config: config.array_inline_threshold = array_inline_threshold with asdf.AsdfFile(tree) as af: af.write_to(file_path) assert len(list(af.blocks.inline_blocks)) == inline_blocks assert len(list(af.blocks.internal_blocks)) == internal_blocks
def test_resource_mappings(): with asdf.config_context() as config: core_mappings = resource.get_core_resource_mappings() default_mappings = config.resource_mappings assert len(default_mappings) >= len(core_mappings) new_mapping = {"http://somewhere.org/schemas/foo-1.0.0": b"foo"} config.add_resource_mapping(new_mapping) assert len(config.resource_mappings) == len(default_mappings) + 1 assert new_mapping in config.resource_mappings config.reset_resources() assert len(config.resource_mappings) == len(default_mappings)
def test_serialize_custom_type(tmpdir): with asdf.config_context() as config: config.add_resource_mapping({FOO_SCHEMA_URI: FOO_SCHEMA}) config.add_extension(FooExtension()) path = str(tmpdir / "test.asdf") af = asdf.AsdfFile() af["foo"] = Foo("bar") af.write_to(path) with asdf.open(path) as af2: assert af2["foo"].value == "bar" with pytest.raises(asdf.ValidationError): af["foo"] = Foo(12) af.write_to(path)
def test_asdf_file_version(): with config_context() as config: config.default_version = "1.2.0" af = AsdfFile() assert af.version == AsdfVersion("1.2.0") assert af.version_string == "1.2.0" af = AsdfFile(version="1.3.0") assert af.version == AsdfVersion("1.3.0") assert af.version_string == "1.3.0" af = AsdfFile(version=AsdfVersion("1.3.0")) assert af.version == AsdfVersion("1.3.0") assert af.version_string == "1.3.0" with pytest.raises(ValueError): AsdfFile(version="0.5.4") with pytest.raises(ValueError): AsdfFile(version=AsdfVersion("0.5.4")) af = AsdfFile() af.version = "1.3.0" assert af.version == AsdfVersion("1.3.0") assert af.version_string == "1.3.0" af.version = AsdfVersion("1.4.0") assert af.version == AsdfVersion("1.4.0") assert af.version_string == "1.4.0" with pytest.raises(ValueError): af.version = "0.5.4" with pytest.raises(ValueError): af.version = AsdfVersion("2.5.4") af.version = "1.0.0" assert af.version_map["tags"][ "tag:stsci.edu:asdf/core/asdf"] == "1.0.0" af.version = "1.2.0" assert af.version_map["tags"][ "tag:stsci.edu:asdf/core/asdf"] == "1.1.0"
def test_resource_manager(): with asdf.config_context() as config: assert "http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager assert b"http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager["http://stsci.edu/schemas/asdf/core/asdf-1.1.0"] assert "http://somewhere.org/schemas/foo-1.0.0" not in config.resource_manager config.add_resource_mapping({"http://somewhere.org/schemas/foo-1.0.0": b"foo"}) assert "http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager assert b"http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager["http://stsci.edu/schemas/asdf/core/asdf-1.1.0"] assert "http://somewhere.org/schemas/foo-1.0.0" in config.resource_manager assert config.resource_manager["http://somewhere.org/schemas/foo-1.0.0"] == b"foo" config.reset_resources() assert "http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager assert b"http://stsci.edu/schemas/asdf/core/asdf-1.1.0" in config.resource_manager["http://stsci.edu/schemas/asdf/core/asdf-1.1.0"] assert "http://somewhere.org/schemas/foo-1.0.0" not in config.resource_manager
def test_config_context_threaded(): assert get_config().validate_on_read is True thread_value = None def worker(): nonlocal thread_value thread_value = get_config().validate_on_read with asdf.config_context() as config: config.validate_on_read = False pass with asdf.config_context() as config: config.validate_on_read = False thread = threading.Thread(target=worker) thread.start() thread.join() assert thread_value is True assert get_config().validate_on_read is True
def test_get_extension(): class FooExtension: extension_uri = "asdf://somewhere.org/extensions/foo-1.0" types = [] tag_mapping = [] url_mapping = [] with asdf.config_context() as config: with pytest.raises(KeyError): config.get_extension(FooExtension.extension_uri) extension = FooExtension() config.add_extension(extension) config.get_extension(FooExtension.extension_uri).delegate is extension # Extensions added later take precedence: duplicate_extension = FooExtension() config.add_extension(extension) config.get_extension( FooExtension.extension_uri).delegate is duplicate_extension
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_asdf_file_extensions(): af = AsdfFile() assert af.extensions == get_config().extensions extension = TestExtension( extension_uri="asdf://somewhere.org/extensions/foo-1.0") for arg in ([extension], extension, AsdfExtensionList([extension])): af = AsdfFile(extensions=arg) assert af.extensions[0] == ExtensionProxy(extension) assert af.extensions[1:] == get_config().extensions af = AsdfFile() af.extensions = arg assert af.extensions[0] == ExtensionProxy(extension) assert af.extensions[1:] == get_config().extensions # This use case is a little silly, but in the future it will be # possible to disable extensions globally and passing the URI # will enable them on an individual file basis. Currently all # we can do with the URI is put the extension at the head of # list so that it has priority. with config_context() as config: config.add_extension(extension) for arg in ([extension.extension_uri], extension.extension_uri): af = AsdfFile(extensions=arg) assert af.extensions[0] == ExtensionProxy(extension) af = AsdfFile() af.extensions = arg assert af.extensions[0] == ExtensionProxy(extension) for arg in (object(), [object()]): with pytest.raises(TypeError): AsdfFile(extensions=arg) with pytest.raises(KeyError): AsdfFile(extensions="not-a-URI")
def test_load_schema_with_asdf_uri_scheme(): subschema_content = """%YAML 1.1 --- $schema: http://stsci.edu/schemas/asdf/asdf-schema-1.0.0 id: asdf://somewhere.org/schemas/bar bar: type: string ... """ content = """%YAML 1.1 --- $schema: http://stsci.edu/schemas/asdf/asdf-schema-1.0.0 id: asdf://somewhere.org/schemas/foo definitions: local_bar: type: string type: object properties: bar: $ref: asdf://somewhere.org/schemas/bar#/bar local_bar: $ref: '#/definitions/local_bar' ... """ with asdf.config_context() as config: config.add_resource_mapping( {"asdf://somewhere.org/schemas/foo": content}) config.add_resource_mapping( {"asdf://somewhere.org/schemas/bar": subschema_content}) schema_tree = schema.load_schema("asdf://somewhere.org/schemas/foo") instance = {"bar": "baz", "local_bar": "foz"} schema.validate(instance, schema=schema_tree) with pytest.raises(ValidationError): schema.validate({"bar": 12}, schema=schema_tree)
def test_extensions(): with asdf.config_context() as config: original_extensions = config.extensions assert any( isinstance(e.delegate, BuiltinExtension) for e in original_extensions) class FooExtension: types = [] tag_mapping = [] url_mapping = [] new_extension = FooExtension() class BarExtension: extension_uri = "asdf://somewhere.org/extensions/bar-1.0" types = [] tag_mapping = [] url_mapping = [] uri_extension = BarExtension() # Add an extension: config.add_extension(new_extension) assert len(config.extensions) == len(original_extensions) + 1 assert any(e for e in config.extensions if e.delegate is new_extension) # Adding an extension should be idempotent: config.add_extension(new_extension) assert len(config.extensions) == len(original_extensions) + 1 # Even when wrapped: config.add_extension(ExtensionProxy(new_extension)) assert len(config.extensions) == len(original_extensions) + 1 # Remove an extension: config.remove_extension(new_extension) assert len(config.extensions) == len(original_extensions) # Removing should work when wrapped: config.add_extension(new_extension) config.remove_extension(ExtensionProxy(new_extension)) assert len(config.extensions) == len(original_extensions) # And also by URI: config.add_extension(uri_extension) config.remove_extension(uri_extension.extension_uri) assert len(config.extensions) == len(original_extensions) # And also by URI pattern: config.add_extension(uri_extension) config.remove_extension("asdf://somewhere.org/extensions/*") assert len(config.extensions) == len(original_extensions) # Remove by the name of the extension's package: config.add_extension(ExtensionProxy(new_extension, package_name="foo")) config.add_extension(ExtensionProxy(uri_extension, package_name="foo")) config.remove_extension(package="foo") assert len(config.extensions) == len(original_extensions) # Can combine remove filters: config.add_extension(ExtensionProxy(new_extension, package_name="foo")) config.add_extension(ExtensionProxy(uri_extension, package_name="foo")) config.remove_extension(uri_extension.extension_uri, package="foo") assert len(config.extensions) == len(original_extensions) + 1 # ... but not omit both: with pytest.raises(ValueError): config.remove_extension() # Removing an extension should be idempotent: config.add_extension(new_extension) config.remove_extension(new_extension) config.remove_extension(new_extension) assert len(config.extensions) == len(original_extensions) # Resetting should get rid of any additions: config.add_extension(new_extension) config.add_extension(FooExtension()) config.reset_extensions() assert len(config.extensions) == len(original_extensions)
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)
def worker(): nonlocal thread_value thread_value = get_config().validate_on_read with asdf.config_context() as config: config.validate_on_read = False pass