diff --git a/asdf/_asdf.py b/asdf/_asdf.py index 41dac5bed..3a5d4a3fb 100644 --- a/asdf/_asdf.py +++ b/asdf/_asdf.py @@ -18,7 +18,6 @@ from ._helpers import validate_version from .config import config_context, get_config from .exceptions import ( - AsdfDeprecationWarning, AsdfManifestURIMismatchWarning, AsdfPackageVersionWarning, AsdfWarning, @@ -31,21 +30,6 @@ from .util import NotSet -def __getattr__(name): - if name == "SerializationContext": - warnings.warn( - "importing SerializationContext from asdf.asdf is deprecated. " - "Please import SerializationContext from asdf.extension", - AsdfDeprecationWarning, - ) - from .extension._serialization_context import SerializationContext - - return SerializationContext - - msg = f"module {__name__!r} has no attribute {name!r}" - raise AttributeError(msg) - - def _get_asdf_library_info(): """ Get information about asdf to include in the asdf_library entry @@ -72,9 +56,7 @@ def __init__( uri=None, extensions=None, version=None, - ignore_version_mismatch=NotSet, ignore_unrecognized_tag=False, - ignore_implicit_conversion=NotSet, memmap=True, lazy_load=True, custom_schema=None, @@ -100,22 +82,10 @@ def __init__( The ASDF Standard version. If not provided, defaults to the configured default version. See `asdf.config.AsdfConfig.default_version`. - ignore_version_mismatch : bool, optional - Deprecated and unused. This setting does nothing since asdf 3.0.0 - When `True`, do not raise warnings for mismatched schema versions. - Set to `True` by default. - ignore_unrecognized_tag : bool, optional When `True`, do not raise warnings for unrecognized tags. Set to `False` by default. - ignore_implicit_conversion : bool - DEPRECATED - When `True`, do not raise warnings when types in the tree are - implicitly converted into a serializable object. The motivating - case for this is currently ``namedtuple``, which cannot be serialized - as-is. - memmap : bool, optional When `True`, when reading files, attempt to memmap underlying data arrays when possible. Defaults to ``True``. @@ -155,14 +125,7 @@ def __init__( else: self._custom_schema = None - if ignore_version_mismatch is not NotSet: - warnings.warn( - "ignore_version_mismatch is deprecated and has done nothing since asdf 3.0.0", - AsdfDeprecationWarning, - ) - self._ignore_unrecognized_tag = ignore_unrecognized_tag - self._ignore_implicit_conversion = ignore_implicit_conversion # Context of a call to treeutil.walk_and_modify, needed in the AsdfFile # in case walk_and_modify is re-entered by extension code (via @@ -177,12 +140,6 @@ def __init__( self._closed = False self._external_asdf_by_uri = {} self._blocks = BlockManager(uri=uri, lazy_load=lazy_load, memmap=memmap) - # this message is passed into find_references to only warn if - # a reference was found - find_ref_warning_msg = ( - "find_references during AsdfFile.__init__ is deprecated. " - "call AsdfFile.find_references after AsdfFile.__init__" - ) if tree is None: # Bypassing the tree property here, to avoid validating # an empty tree. @@ -196,21 +153,12 @@ def __init__( self._blocks._uri = tree.uri # Set directly to self._tree (bypassing property), since # we can assume the other AsdfFile is already valid. - self._tree = tree.tree - self.find_references(_warning_msg=find_ref_warning_msg) + # Call "walk_and_modify" here to use it's logic for + # creating a "copy" of the other tree. This mimics what was previously + # a call to find_references (which we longer do in AsdfFile.__init__) + self._tree = treeutil.walk_and_modify(tree.tree, lambda o: o) else: self._tree = AsdfObject(tree) - try: - self.validate() - except ValidationError: - warnings.warn( - "Validation during AsdfFile.__init__ is deprecated. " - "Please use AsdfFile.validate to validate the tree", - AsdfDeprecationWarning, - ) - raise - - self.find_references(_warning_msg=find_ref_warning_msg) self._comments = [] @@ -252,14 +200,6 @@ def version_string(self): """ return str(self._version) - @property - def version_map(self): - warnings.warn( - "AsdfFile.version_map is deprecated. Please use the extension_manager", - AsdfDeprecationWarning, - ) - return versioning._get_version_map(self.version_string) - @property def extensions(self): """ @@ -619,16 +559,7 @@ def tree(self): @tree.setter def tree(self, tree): - asdf_object = AsdfObject(tree) - # Only perform custom validation if the tree is not empty - try: - self._validate(asdf_object, custom=bool(tree)) - except ValidationError: - warnings.warn( - "Validation on tree assignment is deprecated. Please use AsdfFile.validate", AsdfDeprecationWarning - ) - raise - self._tree = asdf_object + self._tree = AsdfObject(tree) def keys(self): return self.tree.keys() @@ -956,9 +887,6 @@ def _open_asdf( # to select the correct tag for us. tree = yamlutil.custom_tree_to_tagged_tree(AsdfObject(), self) - find_ref_warning_msg = "find_references during open is deprecated. call AsdfFile.find_references after open" - tree = reference.find_references(tree, self, _warning_msg=find_ref_warning_msg) - if self.version <= versioning.FILL_DEFAULTS_MAX_VERSION and get_config().legacy_fill_schema_defaults: schema.fill_defaults(tree, self, reading=True) @@ -1325,49 +1253,22 @@ def write_to( if version is not None: self.version = previous_version - def find_references(self, _warning_msg=False): + def find_references(self): """ Finds all external "JSON References" in the tree and converts them to ``reference.Reference`` objects. """ # Set directly to self._tree, since it doesn't need to be re-validated. - self._tree = reference.find_references(self._tree, self, _warning_msg=_warning_msg) + self._tree = reference.find_references(self._tree, self) - def resolve_references(self, **kwargs): + def resolve_references(self): """ Finds all external "JSON References" in the tree, loads the external content, and places it directly in the tree. Saving a ASDF file after this operation means it will have no external references, and will be completely self-contained. """ - if len(kwargs): - warnings.warn("Passing kwargs to resolve_references is deprecated and does nothing", AsdfDeprecationWarning) self._tree = reference.resolve_references(self._tree, self) - try: - self.validate() - except ValidationError: - warnings.warn( - "Validation during resolve_references is deprecated. " - "Please use AsdfFile.validate after resolve_references to validate the resolved tree", - AsdfDeprecationWarning, - ) - raise - - def resolve_and_inline(self): - """ - Resolves all external references and inlines all data. This - produces something that, when saved, is a 100% valid YAML - file. - """ - warnings.warn( - "resolve_and_inline is deprecated. " - "Use AsdfFile.resolve_references and all_array_storage=inline " - "during AsdfFile.write_to", - AsdfDeprecationWarning, - ) - self.resolve_references() - for b in self._blocks.blocks: - self.set_array_storage(b.data, "inline") def fill_defaults(self): """ @@ -1607,7 +1508,6 @@ def open_asdf( mode=None, validate_checksums=False, extensions=None, - ignore_version_mismatch=NotSet, ignore_unrecognized_tag=False, _force_raw_types=False, memmap=True, @@ -1643,11 +1543,6 @@ def open_asdf( Additional extensions to use when reading and writing the file. May be an `asdf.extension.Extension` or a `list` of extensions. - ignore_version_mismatch : bool, optional - Deprecated and unused. This setting does nothing since asdf 3.0.0 - When `True`, do not raise warnings for mismatched schema versions. - Set to `True` by default. - ignore_unrecognized_tag : bool, optional When `True`, do not raise warnings for unrecognized tags. Set to `False` by default. @@ -1713,7 +1608,6 @@ def open_asdf( mode = "r" instance = AsdfFile( - ignore_version_mismatch=ignore_version_mismatch, ignore_unrecognized_tag=ignore_unrecognized_tag, memmap=memmap, lazy_load=lazy_load, diff --git a/asdf/_convenience.py b/asdf/_convenience.py index d84bcd525..a0f57dbfd 100644 --- a/asdf/_convenience.py +++ b/asdf/_convenience.py @@ -18,7 +18,7 @@ def info(node_or_path, max_rows=DEFAULT_MAX_ROWS, max_cols=DEFAULT_MAX_COLS, sho Parameters ---------- - node_or_path : str, pathlib.Path, asdf.asdf.AsdfFile, or any ASDF tree node + node_or_path : str, pathlib.Path, asdf.AsdfFile, or any ASDF tree node The tree or sub-tree to render. Strings and Path objects will first be passed to asdf.open(...). diff --git a/asdf/_tests/_regtests/test_1715.py b/asdf/_tests/_regtests/test_1715.py index 18c140eaa..5c6da8a3b 100644 --- a/asdf/_tests/_regtests/test_1715.py +++ b/asdf/_tests/_regtests/test_1715.py @@ -1,5 +1,3 @@ -import pytest - import asdf @@ -22,7 +20,6 @@ def test_id_in_tree_breaks_ref(tmp_path): af["myref"] = {"$ref": "external.asdf#/thing"} af.write_to(main_fn) - with pytest.warns(asdf.exceptions.AsdfDeprecationWarning, match="find_references"): - with asdf.open(main_fn) as af: - af.resolve_references() - assert af["myref"] == 42 + with asdf.open(main_fn) as af: + af.resolve_references() + assert af["myref"] == 42 diff --git a/asdf/_tests/test_api.py b/asdf/_tests/test_api.py index 2b95734f3..b33059511 100644 --- a/asdf/_tests/test_api.py +++ b/asdf/_tests/test_api.py @@ -4,7 +4,6 @@ import os import pathlib import sys -import warnings import numpy as np import pytest @@ -12,7 +11,7 @@ import asdf from asdf import config_context, get_config, treeutil, versioning -from asdf.exceptions import AsdfDeprecationWarning, AsdfPackageVersionWarning, ValidationError +from asdf.exceptions import AsdfPackageVersionWarning, ValidationError from asdf.extension import ExtensionProxy from asdf.resource import ResourceMappingProxy from asdf.testing.helpers import roundtrip_object, yaml_to_asdf @@ -261,9 +260,8 @@ def test_context_handler_resolve_and_inline(tmp_path): ff.write_to(str(tempname)) with asdf.open(tempname) as newf: - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "resolve_and_inline is deprecated", AsdfDeprecationWarning) - newf.resolve_and_inline() + newf.resolve_references() + newf.set_array_storage(newf["random"], "inline") with pytest.raises(OSError, match=r"Cannot access data from closed ASDF file"): newf.tree["random"][0] diff --git a/asdf/_tests/test_asdf.py b/asdf/_tests/test_asdf.py index 3945a6583..3fa21ff3d 100644 --- a/asdf/_tests/test_asdf.py +++ b/asdf/_tests/test_asdf.py @@ -6,7 +6,7 @@ from asdf._asdf import AsdfFile, open_asdf from asdf._entry_points import get_extensions from asdf._tests._helpers import assert_tree_match -from asdf.exceptions import AsdfDeprecationWarning, AsdfWarning +from asdf.exceptions import AsdfWarning from asdf.extension import ExtensionProxy from asdf.testing.helpers import yaml_to_asdf from asdf.versioning import AsdfVersion @@ -102,14 +102,6 @@ def test_asdf_file_version(): with pytest.raises(ValueError, match=r"ASDF Standard version .* is not supported by asdf==.*"): af.version = AsdfVersion("2.5.4") - af.version = "1.0.0" - with pytest.warns(AsdfDeprecationWarning, match="AsdfFile.version_map is deprecated"): - assert af.version_map["tags"]["tag:stsci.edu:asdf/core/asdf"] == "1.0.0" - - af.version = "1.2.0" - with pytest.warns(AsdfDeprecationWarning, match="AsdfFile.version_map is deprecated"): - assert af.version_map["tags"]["tag:stsci.edu:asdf/core/asdf"] == "1.1.0" - def test_asdf_file_extensions(): af = AsdfFile() diff --git a/asdf/_tests/test_deprecated.py b/asdf/_tests/test_deprecated.py index 2a13151c3..e69de29bb 100644 --- a/asdf/_tests/test_deprecated.py +++ b/asdf/_tests/test_deprecated.py @@ -1,154 +0,0 @@ -import sys -import warnings - -import numpy as np -import pytest - -import asdf -import asdf.testing.helpers -from asdf.exceptions import AsdfDeprecationWarning, ValidationError - - -def test_asdf_stream_deprecation(): - with pytest.warns(AsdfDeprecationWarning, match="asdf.stream is deprecated"): - if "asdf.stream" in sys.modules: - del sys.modules["asdf.stream"] - import asdf.stream # noqa: F401 - - -def test_asdf_asdf_SerializationContext_import_deprecation(): - with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", - category=AsdfDeprecationWarning, - message="asdf.asdf is deprecated. Please use asdf.AsdfFile and asdf.open", - ) - warnings.filterwarnings( - "ignore", - category=AsdfDeprecationWarning, - message="asdf.asdf is deprecated", - ) - with pytest.warns(AsdfDeprecationWarning, match="importing SerializationContext from asdf.asdf"): - from asdf.asdf import SerializationContext # noqa: F401 - - -def test_asdf_util_human_list_deprecation(): - with pytest.warns(AsdfDeprecationWarning, match="asdf.util.human_list is deprecated"): - asdf.util.human_list("a") - - -def test_asdf_util_resolve_name_deprecation(): - with pytest.warns(AsdfDeprecationWarning, match="asdf.util.resolve_name is deprecated"): - asdf.util.resolve_name("asdf.AsdfFile") - - -def test_asdf_util_minversion_deprecation(): - with pytest.warns(AsdfDeprecationWarning, match="asdf.util.minversion is deprecated"): - asdf.util.minversion("yaml", "3.1") - - -def test_asdf_util_iter_subclasses_deprecation(): - with pytest.warns(AsdfDeprecationWarning, match="asdf.util.iter_subclasses is deprecated"): - list(asdf.util.iter_subclasses(asdf.AsdfFile)) - - -def test_asdf_asdf_deprecation(): - with pytest.warns(AsdfDeprecationWarning, match="asdf.asdf is deprecated"): - if "asdf.asdf" in sys.modules: - del sys.modules["asdf.asdf"] - import asdf.asdf # noqa: F401 - - -def test_resolve_and_inline_deprecation(): - with pytest.warns(AsdfDeprecationWarning, match="resolve_and_inline is deprecated"): - af = asdf.AsdfFile({"arr": np.arange(42)}) - af.resolve_and_inline() - - -def test_find_references_during_init_deprecation(): - tree = {"a": 1, "b": {"$ref": "#"}} - with pytest.warns(AsdfDeprecationWarning, match="find_references during AsdfFile.__init__"): - asdf.AsdfFile(tree) - - -def test_find_references_during_open_deprecation(tmp_path): - fn = tmp_path / "test.asdf" - af = asdf.AsdfFile() - af["a"] = 1 - af["b"] = {"$ref": "#"} - af.write_to(fn) - with pytest.warns(AsdfDeprecationWarning, match="find_references during open"): - with asdf.open(fn) as af: - pass - - -def test_asdf_util_is_primitive_deprecation(): - with pytest.warns(AsdfDeprecationWarning, match="asdf.util.is_primitive is deprecated"): - asdf.util.is_primitive(1) - - -def test_AsdfFile_tree_assignment_validation_deprecation(): - af = asdf.AsdfFile() - with ( - pytest.warns(AsdfDeprecationWarning, match="Validation on tree assignment is deprecated"), - pytest.raises(ValidationError), - ): - af.tree = {"history": 42} - - -def test_AsdfFile_resolve_references_validation_deprecation(): - af = asdf.AsdfFile() - af._tree["history"] = 42 - with ( - pytest.warns(AsdfDeprecationWarning, match="Validation during resolve_references is deprecated"), - pytest.raises(ValidationError), - ): - af.resolve_references() - - -def test_AsdfFile_resolve_references_kwargs_deprecation(): - af = asdf.AsdfFile() - with pytest.warns(AsdfDeprecationWarning, match="Passing kwargs to resolve_references is deprecated"): - af.resolve_references(foo=42) - - -def test_AsdfFile_init_validation_deprecation(): - with ( - pytest.warns(AsdfDeprecationWarning, match="Validation during AsdfFile.__init__ is deprecated"), - pytest.raises(ValidationError), - ): - asdf.AsdfFile({"history": 42}) - - -def test_asdffile_version_map_deprecation(): - af = asdf.AsdfFile() - with pytest.warns(AsdfDeprecationWarning, match="AsdfFile.version_map is deprecated"): - af.version_map - - -def test_format_tag_deprecation(): - with pytest.warns(AsdfDeprecationWarning, match="format_tag is deprecated"): - asdf.testing.helpers.format_tag("stsci.edu", "asdf", "1.0.0", "fits/fits") - - -def test_asdf_util_filepath_to_url_deprecation(tmp_path): - with pytest.warns(AsdfDeprecationWarning, match="asdf.util.filepath_to_url is deprecated"): - asdf.util.filepath_to_url(str(tmp_path)) - - -@pytest.mark.parametrize("value", [True, False]) -def test_AsdfFile_ignore_implicit_conversion_deprecation(value): - with pytest.warns(AsdfDeprecationWarning, match="ignore_implicit_conversion is deprecated"): - asdf.AsdfFile({"a": 1}, ignore_implicit_conversion=value) - - -@pytest.mark.parametrize("value", [True, False]) -def test_walk_and_modify_ignore_implicit_conversion_deprecation(value): - with pytest.warns(AsdfDeprecationWarning, match="ignore_implicit_conversion is deprecated"): - asdf.treeutil.walk_and_modify({}, lambda obj: obj, ignore_implicit_conversion=value) - - -@pytest.mark.parametrize("value", [True, False]) -def test_ignore_version_mismatch_deprecation(value): - with pytest.warns(AsdfDeprecationWarning, match="ignore_version_mismatch is deprecated"): - asdf.AsdfFile({}, ignore_version_mismatch=value) diff --git a/asdf/_tests/test_extension.py b/asdf/_tests/test_extension.py index d9a16c54d..d2e294b4f 100644 --- a/asdf/_tests/test_extension.py +++ b/asdf/_tests/test_extension.py @@ -1,3 +1,4 @@ +import collections import fractions import sys @@ -1047,3 +1048,33 @@ class MailboxExtension: converter = extension_manager.get_converter_for_type(mailbox.Mailbox) assert isinstance(converter.delegate, MailboxConverter) + + +def test_named_tuple_extension(): + Point = collections.namedtuple("Point", ["x", "y"]) + + class PointConverter: + tags = ["asdf://example.com/tags/point-1.0.0"] + types = [Point] + + def to_yaml_tree(self, obj, tag, ctx): + return list(obj) + + def from_yaml_tree(self, node, tag, ctx): + return Point(*node) + + class PointExtension: + tags = PointConverter.tags + converters = [PointConverter()] + extension_uri = "asdf://example.com/extensions/point-1.0.0" + + pt = Point(1, 2) + + # without the extension we can't serialize this + with pytest.raises(AsdfSerializationError, match="is not serializable by asdf"): + roundtrip_object(pt) + + with config_context() as cfg: + cfg.add_extension(PointExtension()) + rpt = roundtrip_object(pt) + assert isinstance(rpt, Point) diff --git a/asdf/_tests/test_file_format.py b/asdf/_tests/test_file_format.py index 16f0aad48..c2d43365c 100644 --- a/asdf/_tests/test_file_format.py +++ b/asdf/_tests/test_file_format.py @@ -99,7 +99,6 @@ def test_empty_file(): assert len(ff._blocks.blocks) == 0 -@pytest.mark.filterwarnings("ignore::asdf.exceptions.AsdfDeprecationWarning") def test_not_asdf_file(): buff = io.BytesIO(b"SIMPLE") buff.seek(0) diff --git a/asdf/_tests/test_reference.py b/asdf/_tests/test_reference.py index 8cbfb16b0..f618865fd 100644 --- a/asdf/_tests/test_reference.py +++ b/asdf/_tests/test_reference.py @@ -7,7 +7,6 @@ import asdf from asdf import reference -from asdf.exceptions import AsdfDeprecationWarning from asdf.tags.core import ndarray from ._helpers import assert_tree_match @@ -80,8 +79,6 @@ def do_asserts(ff): assert_array_equal(ff.tree["internal"], exttree["cool_stuff"]["a"]) with asdf.AsdfFile({}, uri=(tmp_path / "main.asdf").as_uri()) as ff: - # avoid passing tree to AsdfFile to avoid the deprecation warning, this can be updated - # when automatic find_references on AsdfFile.__init__ is removed ff.tree = tree ff.find_references() do_asserts(ff) @@ -89,14 +86,12 @@ def do_asserts(ff): internal_path = os.path.join(str(tmp_path), "main.asdf") ff.write_to(internal_path) - with pytest.warns(AsdfDeprecationWarning, match="find_references during open"), asdf.open(internal_path) as ff: - # this can be updated to add a find_references call when the deprecated automatic - # find_references on open is removed + with asdf.open(internal_path) as ff: + ff.find_references() do_asserts(ff) - with pytest.warns(AsdfDeprecationWarning, match="find_references during open"), asdf.open(internal_path) as ff: - # this can be updated to add a find_references call when the deprecated automatic - # find_references on open is removed + with asdf.open(internal_path) as ff: + ff.find_references() assert len(ff._external_asdf_by_uri) == 0 ff.resolve_references() assert len(ff._external_asdf_by_uri) == 2 @@ -124,16 +119,12 @@ def do_asserts(ff): def test_external_reference_invalid(tmp_path): tree = {"foo": {"$ref": "fail.asdf"}} - # avoid passing tree to AsdfFile to avoid the deprecation warning, this can be updated - # when automatic find_references on AsdfFile.__init__ is removed ff = asdf.AsdfFile() ff.tree = tree ff.find_references() with pytest.raises(ValueError, match=r"Resolved to relative URL"): ff.resolve_references() - # avoid passing tree to AsdfFile to avoid the deprecation warning, this can be updated - # when automatic find_references on AsdfFile.__init__ is removed ff = asdf.AsdfFile({}, uri="http://httpstat.us/404") ff.tree = tree ff.find_references() @@ -141,8 +132,6 @@ def test_external_reference_invalid(tmp_path): with pytest.raises(IOError, match=msg): ff.resolve_references() - # avoid passing tree to AsdfFile to avoid the deprecation warning, this can be updated - # when automatic find_references on AsdfFile.__init__ is removed ff = asdf.AsdfFile({}, uri=(tmp_path / "main.asdf").as_uri()) ff.tree = tree ff.find_references() @@ -158,8 +147,6 @@ def test_external_reference_invalid_fragment(tmp_path): tree = {"foo": {"$ref": "external.asdf#/list_of_stuff/a"}} - # avoid passing tree to AsdfFile to avoid the deprecation warning, this can be updated - # when automatic find_references on AsdfFile.__init__ is removed with asdf.AsdfFile({}, uri=(tmp_path / "main.asdf").as_uri()) as ff: ff.tree = tree ff.find_references() @@ -168,8 +155,6 @@ def test_external_reference_invalid_fragment(tmp_path): tree = {"foo": {"$ref": "external.asdf#/list_of_stuff/3"}} - # avoid passing tree to AsdfFile to avoid the deprecation warning, this can be updated - # when automatic find_references on AsdfFile.__init__ is removed with asdf.AsdfFile({}, uri=(tmp_path / "main.asdf").as_uri()) as ff: ff.tree = tree ff.find_references() @@ -194,12 +179,8 @@ def test_make_reference(tmp_path): ff.write_to(os.path.join(str(tmp_path), "source.asdf")) - with ( - pytest.warns(AsdfDeprecationWarning, match="find_references during open"), - asdf.open(os.path.join(str(tmp_path), "source.asdf")) as ff, - ): - # this can be updated to add a find_references call when the deprecated automatic - # find_references on open is removed + with (asdf.open(os.path.join(str(tmp_path), "source.asdf")) as ff,): + ff.find_references() assert ff.tree["ref"]._uri == "external.asdf#f~0o~0o~1/a" @@ -208,8 +189,7 @@ def test_internal_reference(tmp_path): tree = {"foo": 2, "bar": {"$ref": "#"}} - with pytest.warns(AsdfDeprecationWarning, match="find_references during AsdfFile.__init__"): - ff = asdf.AsdfFile(tree) + ff = asdf.AsdfFile(tree) ff.find_references() assert isinstance(ff.tree["bar"], reference.Reference) ff.resolve_references() diff --git a/asdf/_tests/test_schema.py b/asdf/_tests/test_schema.py index a72732701..b8b8bef61 100644 --- a/asdf/_tests/test_schema.py +++ b/asdf/_tests/test_schema.py @@ -8,7 +8,7 @@ import asdf from asdf import config_context, constants, get_config, schema, tagged, util, yamlutil -from asdf.exceptions import AsdfConversionWarning, AsdfDeprecationWarning, AsdfWarning, ValidationError +from asdf.exceptions import AsdfConversionWarning, AsdfWarning, ValidationError from asdf.extension import TagDefinition from asdf.testing.helpers import yaml_to_asdf @@ -136,30 +136,6 @@ def test_load_schema(tmp_path): schema.check_schema(schema_tree) -def test_load_schema_with_full_tag(tmp_path): - schema_def = """ -%YAML 1.1 ---- -$schema: "http://stsci.edu/schemas/asdf/asdf-schema-1.0.0" -id: "http://stsci.edu/schemas/asdf/nugatory/nugatory-1.0.0" -tag: "tag:stsci.edu:asdf/nugatory/nugatory-1.0.0" - -type: object -properties: - foobar: - $ref: "tag:stsci.edu:asdf/core/ndarray-1.0.0" - -required: [foobar] -... - """ - schema_path = tmp_path / "nugatory.yaml" - schema_path.write_bytes(schema_def.encode()) - - with pytest.warns(AsdfDeprecationWarning, match="Resolving by tag is deprecated"): - schema_tree = schema.load_schema(str(schema_path), resolve_references=True) - schema.check_schema(schema_tree) - - def test_load_schema_with_file_url(tmp_path): schema_def = """ %YAML 1.1 diff --git a/asdf/_tests/test_util.py b/asdf/_tests/test_util.py index ca64a7a41..97923e793 100644 --- a/asdf/_tests/test_util.py +++ b/asdf/_tests/test_util.py @@ -1,23 +1,11 @@ import contextlib import io -import warnings import numpy as np import pytest import asdf from asdf import generic_io, util -from asdf.exceptions import AsdfDeprecationWarning - - -def test_is_primitive(): - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "asdf.util.is_primitive is deprecated", AsdfDeprecationWarning) - for value in [None, "foo", 1, 1.39, 1 + 1j, True]: - assert util.is_primitive(value) is True - - for value in [[], (), {}, set()]: - assert util.is_primitive(value) is False def test_not_set(): @@ -104,25 +92,6 @@ def read(self, size=-1): assert fd.read() == content -def test_minversion(): - import numpy as np - import yaml - - good_versions = ["1.16", "1.16.1", "1.16.0.dev", "1.16dev"] - bad_versions = ["100000", "100000.2rc1"] - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "asdf.util.minversion", AsdfDeprecationWarning) - for version in good_versions: - assert util.minversion(np, version) - assert util.minversion("numpy", version) - for version in bad_versions: - assert not util.minversion(np, version) - assert not util.minversion("numpy", version) - - assert util.minversion(yaml, "3.1") - assert util.minversion("yaml", "3.1") - - @pytest.mark.parametrize("input_type", ["filename", "binary_file", "generic_file"]) @pytest.mark.parametrize("tagged", [True, False]) def test_load_yaml(tmp_path, input_type, tagged): diff --git a/asdf/_tests/test_versioning.py b/asdf/_tests/test_versioning.py index 9f702a195..58e419a30 100644 --- a/asdf/_tests/test_versioning.py +++ b/asdf/_tests/test_versioning.py @@ -1,10 +1,6 @@ from itertools import combinations -import pytest - -from asdf.exceptions import AsdfDeprecationWarning from asdf.versioning import ( - AsdfSpec, AsdfVersion, asdf_standard_development_version, default_version, @@ -171,113 +167,3 @@ def test_version_and_tuple_inequality(): assert (2, 0, 1) >= version assert (2, 1, 0) >= version assert (2, 1, 1) >= version - - -def test_spec_version_match(): - with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): - spec = AsdfSpec(">=1.1.0") - - assert spec.match(AsdfVersion("1.1.0")) - assert spec.match(AsdfVersion("1.2.0")) - assert not spec.match(AsdfVersion("1.0.0")) - assert not spec.match(AsdfVersion("1.0.9")) - - -def test_spec_version_select(): - with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): - spec = AsdfSpec(">=1.1.0") - - versions = [AsdfVersion(x) for x in ["1.0.0", "1.0.9", "1.1.0", "1.2.0"]] - assert spec.select(versions) == "1.2.0" - assert spec.select(versions[:-1]) == "1.1.0" - assert spec.select(versions[:-2]) is None - - -def test_spec_version_filter(): - with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): - spec = AsdfSpec(">=1.1.0") - - versions = [AsdfVersion(x) for x in ["1.0.0", "1.0.9", "1.1.0", "1.2.0"]] - for x, y in zip(spec.filter(versions), ["1.1.0", "1.2.0"]): - assert x == y - - -def test_spec_string_match(): - with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): - spec = AsdfSpec(">=1.1.0") - - assert spec.match("1.1.0") - assert spec.match("1.2.0") - assert not spec.match("1.0.0") - assert not spec.match("1.0.9") - - -def test_spec_string_select(): - with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): - spec = AsdfSpec(">=1.1.0") - - versions = ["1.0.0", "1.0.9", "1.1.0", "1.2.0"] - assert spec.select(versions) == "1.2.0" - assert spec.select(versions[:-1]) == "1.1.0" - assert spec.select(versions[:-2]) is None - - -def test_spec_string_filter(): - with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): - spec = AsdfSpec(">=1.1.0") - - versions = ["1.0.0", "1.0.9", "1.1.0", "1.2.0"] - for x, y in zip(spec.filter(versions), ["1.1.0", "1.2.0"]): - assert x == y - - -def test_spec_tuple_match(): - with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): - spec = AsdfSpec(">=1.1.0") - - assert spec.match((1, 1, 0)) - assert spec.match((1, 2, 0)) - assert not spec.match((1, 0, 0)) - assert not spec.match((1, 0, 9)) - - -def test_spec_tuple_select(): - with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): - spec = AsdfSpec(">=1.1.0") - - versions = [(1, 0, 0), (1, 0, 9), (1, 1, 0), (1, 2, 0)] - assert spec.select(versions) == "1.2.0" - assert spec.select(versions[:-1]) == "1.1.0" - assert spec.select(versions[:-2]) is None - - -def test_spec_tuple_filter(): - with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): - spec = AsdfSpec(">=1.1.0") - - versions = [(1, 0, 0), (1, 0, 9), (1, 1, 0), (1, 2, 0)] - for x, y in zip(spec.filter(versions), ["1.1.0", "1.2.0"]): - assert x == y - - -def test_spec_equal(): - """Make sure that equality means match""" - with pytest.warns(AsdfDeprecationWarning, match="AsdfSpec is deprecated"): - spec = AsdfSpec(">=1.2.0") - version0 = AsdfVersion("1.1.0") - version1 = AsdfVersion("1.3.0") - - assert spec != version0 - assert version0 != spec - assert spec == version1 - assert version1 == spec - - assert spec != "1.1.0" - assert "1.1.0" != spec - assert spec == "1.3.0" - assert "1.3.0" == spec - - assert spec != (1, 1, 0) - assert (1, 1, 0) != spec - assert spec == (1, 3, 0) - assert (1, 3, 0) == spec diff --git a/asdf/_tests/test_yaml.py b/asdf/_tests/test_yaml.py index 8c14abff0..b02d4e2f2 100644 --- a/asdf/_tests/test_yaml.py +++ b/asdf/_tests/test_yaml.py @@ -1,8 +1,7 @@ import contextlib import io import re -from collections import OrderedDict, namedtuple -from typing import NamedTuple +from collections import OrderedDict import numpy as np import pytest @@ -10,7 +9,7 @@ import asdf from asdf import tagged, treeutil, yamlutil -from asdf.exceptions import AsdfConversionWarning, AsdfDeprecationWarning, AsdfSerializationError, AsdfWarning +from asdf.exceptions import AsdfConversionWarning, AsdfSerializationError from asdf.testing.helpers import yaml_to_asdf @@ -108,14 +107,6 @@ class Foo: ff.write_to(buff) -def run_tuple_test(input_tree, **kwargs): - content, tree = _roundtrip(input_tree, **kwargs) - - assert b"tuple" not in content - assert isinstance(tree["val"], list) - return content, tree - - def test_python_tuple(): """ We don't want to store tuples as tuples, because that's not a @@ -125,7 +116,10 @@ def test_python_tuple(): input_tree = {"val": (1, 2, 3)} - run_tuple_test(input_tree) + content, tree = _roundtrip(input_tree) + + assert b"tuple" not in content + assert isinstance(tree["val"], list) @contextlib.contextmanager @@ -143,75 +137,6 @@ def multi_warn(category, matches): assert found, f"Did not raise {category} with message matching {match}" -def test_named_tuple_collections(): - """ - Ensure that we are able to serialize a collections.namedtuple. - """ - - nt = namedtuple("TestNamedTuple1", ("one", "two", "three")) - - input_tree = {"val": nt(1, 2, 3)} - - with multi_warn(AsdfDeprecationWarning, ["ignore_implicit_conversion", "implicit conversion is deprecated"]): - run_tuple_test(input_tree, init_kwargs={"ignore_implicit_conversion": True}) - - -def test_named_tuple_typing(): - """ - Ensure that we are able to serialize a typing.NamedTuple. - """ - - class NT(NamedTuple): - one: int - two: int - three: int - - input_tree = {"val": NT(1, 2, 3)} - - with multi_warn(AsdfDeprecationWarning, ["ignore_implicit_conversion", "implicit conversion is deprecated"]): - run_tuple_test(input_tree, init_kwargs={"ignore_implicit_conversion": True}) - - -def test_named_tuple_collections_recursive(): - nt = namedtuple("TestNamedTuple3", ("one", "two", "three")) - - input_tree = {"val": nt(1, 2, np.ones(3))} - - with multi_warn(AsdfDeprecationWarning, ["ignore_implicit_conversion", "implicit conversion is deprecated"]): - _, tree = run_tuple_test(input_tree, init_kwargs={"ignore_implicit_conversion": True}) - assert (tree["val"][2] == np.ones(3)).all() - - -def test_named_tuple_typing_recursive(tmp_path): - class NT(NamedTuple): - one: int - two: int - three: np.ndarray - - input_tree = {"val": NT(1, 2, np.ones(3))} - - with multi_warn(AsdfDeprecationWarning, ["ignore_implicit_conversion", "implicit conversion is deprecated"]): - _, tree = run_tuple_test(input_tree, init_kwargs={"ignore_implicit_conversion": True}) - assert (tree["val"][2] == np.ones(3)).all() - - -def test_implicit_conversion_warning(): - nt = namedtuple("TestTupleWarning", ("one", "two", "three")) - - tree = {"val": nt(1, 2, np.ones(3))} - - with ( - pytest.warns(AsdfWarning, match=r"Failed to serialize instance"), - pytest.warns(AsdfDeprecationWarning, match=r"implicit conversion is deprecated"), - asdf.AsdfFile(tree), - ): - pass - - with multi_warn(AsdfDeprecationWarning, ["ignore_implicit_conversion", "implicit conversion is deprecated"]): - with asdf.AsdfFile(tree, ignore_implicit_conversion=True): - pass - - @pytest.mark.xfail(reason="pyyaml has a bug and does not support tuple keys") def test_python_tuple_key(): """ diff --git a/asdf/asdf.py b/asdf/asdf.py deleted file mode 100644 index 8066ed955..000000000 --- a/asdf/asdf.py +++ /dev/null @@ -1,20 +0,0 @@ -import warnings - -from . import _asdf -from .exceptions import AsdfDeprecationWarning - -warnings.warn( - "asdf.asdf is deprecated. Please use asdf.AsdfFile and asdf.open", - AsdfDeprecationWarning, -) - - -def __getattr__(name): - if hasattr(_asdf, name): - return getattr(_asdf, name) - warnings.warn( - "asdf.asdf is deprecated", - AsdfDeprecationWarning, - ) - msg = f"module {__name__!r} has no attribute {name!r}" - raise AttributeError(msg) diff --git a/asdf/extension/_converter.py b/asdf/extension/_converter.py index 5e9835625..feece7a21 100644 --- a/asdf/extension/_converter.py +++ b/asdf/extension/_converter.py @@ -26,7 +26,7 @@ class Converter(abc.ABC): tags : list of str List of active tags to choose from. Guaranteed to match one of the tag patterns listed in the 'tags' property. - ctx : asdf.asdf.SerializationContext + ctx : asdf.extension.SerializationContext Context of the current serialization request. and return a str, the selected tag (should be one of tags) or diff --git a/asdf/reference.py b/asdf/reference.py index b2f5aad60..35a3182cb 100644 --- a/asdf/reference.py +++ b/asdf/reference.py @@ -4,7 +4,6 @@ and `JSON Pointer standard `__. """ -import warnings import weakref from collections.abc import Sequence from contextlib import suppress @@ -12,7 +11,6 @@ import numpy as np from . import generic_io, treeutil, util -from .exceptions import AsdfDeprecationWarning from .util import _patched_urllib_parse __all__ = ["resolve_fragment", "Reference", "find_references", "resolve_references", "make_reference"] @@ -105,7 +103,7 @@ def __contains__(self, item): return item in self._get_target() -def find_references(tree, ctx, _warning_msg=False): +def find_references(tree, ctx): """ Find all of the JSON references in the tree, and convert them into `Reference` objects. @@ -113,12 +111,10 @@ def find_references(tree, ctx, _warning_msg=False): def do_find(tree): if isinstance(tree, dict) and "$ref" in tree: - if _warning_msg: - warnings.warn(_warning_msg, AsdfDeprecationWarning) return Reference(tree["$ref"], asdffile=ctx) return tree - return treeutil.walk_and_modify(tree, do_find, ignore_implicit_conversion=ctx._ignore_implicit_conversion) + return treeutil.walk_and_modify(tree, do_find) def resolve_references(tree, ctx, **kwargs): @@ -134,7 +130,7 @@ def do_resolve(tree): tree = find_references(tree, ctx) - return treeutil.walk_and_modify(tree, do_resolve, ignore_implicit_conversion=ctx._ignore_implicit_conversion) + return treeutil.walk_and_modify(tree, do_resolve) def make_reference(asdffile, path): diff --git a/asdf/schema.py b/asdf/schema.py index c09bad792..479e72196 100644 --- a/asdf/schema.py +++ b/asdf/schema.py @@ -16,7 +16,7 @@ from . import constants, generic_io, reference, tagged, treeutil, util, versioning, yamlutil from .config import get_config -from .exceptions import AsdfDeprecationWarning, AsdfWarning +from .exceptions import AsdfWarning from .util import _patched_urllib_parse YAML_SCHEMA_METASCHEMA_ID = "http://stsci.edu/schemas/yaml-schema/draft-01" @@ -49,14 +49,8 @@ def _type_to_tag(type_): return None -def _tag_to_uri(input_str): - if not input_str.startswith(constants.STSCI_SCHEMA_TAG_BASE): - return input_str - warnings.warn( - "Resolving by tag is deprecated. Use uris instead of tags", - AsdfDeprecationWarning, - ) - return f"http://stsci.edu/schemas/asdf{input_str[len(constants.STSCI_SCHEMA_TAG_BASE):]}" +def _default_resolver(uri): + return uri def validate_tag(validator, tag_pattern, instance, schema): @@ -239,7 +233,7 @@ def _make_seen_key(self, instance, schema): @lru_cache def _create_validator(validators=YAML_VALIDATORS, visit_repeat_nodes=False): - meta_schema = _load_schema_cached(YAML_SCHEMA_METASCHEMA_ID, _tag_to_uri, False) + meta_schema = _load_schema_cached(YAML_SCHEMA_METASCHEMA_ID, None, False) type_checker = mvalidators.Draft4Validator.TYPE_CHECKER.redefine_many( { @@ -339,9 +333,6 @@ def _load_schema(url): def _make_schema_loader(resolver): - if resolver is None: - resolver = _tag_to_uri - def load_schema(url): # Check if this is a URI provided by the new # Mapping API: @@ -415,9 +406,6 @@ def load_schema(url, resolver=None, resolve_references=False): If ``True``, resolve all ``$ref`` references. """ - if resolver is None: - resolver = _tag_to_uri - # We want to cache the work that went into constructing the schema, but returning # the same object is treacherous, because users who mutate the result will not # expect that they're changing the schema everywhere. @@ -465,7 +453,7 @@ def _safe_resolve(resolver, json_id, uri): @lru_cache def _load_schema_cached(url, resolver, resolve_references): if resolver is None: - resolver = _tag_to_uri + resolver = _default_resolver loader = _make_schema_loader(resolver) schema, url = loader(url) @@ -735,9 +723,9 @@ def applicable_validators(schema): applicable_validators = methodcaller("items") meta_schema_id = schema.get("$schema", YAML_SCHEMA_METASCHEMA_ID) - meta_schema = _load_schema_cached(meta_schema_id, _tag_to_uri, False) + meta_schema = _load_schema_cached(meta_schema_id, None, False) - resolver = _make_jsonschema_refresolver(_tag_to_uri) + resolver = _make_jsonschema_refresolver(_default_resolver) cls = mvalidators.create( meta_schema=meta_schema, diff --git a/asdf/stream.py b/asdf/stream.py deleted file mode 100644 index b66952c65..000000000 --- a/asdf/stream.py +++ /dev/null @@ -1,9 +0,0 @@ -import warnings - -from .exceptions import AsdfDeprecationWarning -from .tags.core.stream import Stream # noqa: F401 - -warnings.warn( - "asdf.stream is deprecated. Please use asdf.tags.core.stream", - AsdfDeprecationWarning, -) diff --git a/asdf/testing/helpers.py b/asdf/testing/helpers.py index 0e31dec65..3dc5fb84b 100644 --- a/asdf/testing/helpers.py +++ b/asdf/testing/helpers.py @@ -2,29 +2,9 @@ Helpers for writing unit tests of ASDF support. """ -import warnings from io import BytesIO import asdf -from asdf.exceptions import AsdfDeprecationWarning -from asdf.versioning import AsdfSpec - - -def format_tag(organization, standard, version, tag_name): - """ - Format a YAML tag. - """ - warnings.warn("format_tag is deprecated", AsdfDeprecationWarning) - - tag = f"tag:{organization}:{standard}/{tag_name}" - - if version is None: - return tag - - if isinstance(version, AsdfSpec): - version = str(version.spec) - - return f"{tag}-{version}" def roundtrip_object(obj, version=None): diff --git a/asdf/treeutil.py b/asdf/treeutil.py index a76fd924b..df013911a 100644 --- a/asdf/treeutil.py +++ b/asdf/treeutil.py @@ -3,12 +3,9 @@ """ import types -import warnings from contextlib import contextmanager from . import lazy_nodes, tagged -from .exceptions import AsdfDeprecationWarning, AsdfWarning -from .util import NotSet __all__ = ["walk", "iter_tree", "walk_and_modify", "get_children", "is_container", "PendingValue", "RemoveNode"] @@ -221,7 +218,7 @@ def __repr__(self): RemoveNode = _RemoveNode() -def walk_and_modify(top, callback, ignore_implicit_conversion=NotSet, postorder=True, _context=None): +def walk_and_modify(top, callback, postorder=True, _context=None): """Modify a tree by walking it with a callback function. It also has the effect of doing a deep copy. @@ -253,24 +250,12 @@ def walk_and_modify(top, callback, ignore_implicit_conversion=NotSet, postorder= before their parents. If `False`, the callable is invoked on the parents first. Defaults to `True`. - ignore_implicit_conversion : bool - DEPRECATED - Controls whether warnings should be issued when implicitly converting a - given type instance in the tree into a serializable object. The primary - case for this is currently ``namedtuple``. - - Defaults to `False`. - Returns ------- tree : object The modified tree. """ - if ignore_implicit_conversion is NotSet: - ignore_implicit_conversion = False - else: - warnings.warn("ignore_implicit_conversion is deprecated", AsdfDeprecationWarning) callback_arity = callback.__code__.co_argcount if callback_arity < 1 or callback_arity > 2: msg = "Expected callback to accept one or two arguments" @@ -360,25 +345,18 @@ def _handle_immutable_sequence(node, json_id): # to yield here. contents = [_recurse(value, json_id) for value in node] - try: - result = node.__class__(contents) - if isinstance(node, tagged.Tagged): - result._tag = node._tag - except TypeError: - # The derived class signature is different, so simply store the - # list representing the contents. Currently this is primarily - # intended to handle namedtuple and NamedTuple instances. - if not ignore_implicit_conversion: - warnings.warn(f"Failed to serialize instance of {type(node)}, converting to list instead", AsdfWarning) - result = contents - warnings.warn("implicit conversion is deprecated. Please instead use a Converter.", AsdfDeprecationWarning) + result = node.__class__(contents) + if isinstance(node, tagged.Tagged): + result._tag = node._tag return result def _handle_children(node, json_id): if isinstance(node, (dict, lazy_nodes.AsdfDictNode)): result = _handle_mapping(node, json_id) - elif isinstance(node, tuple): + # don't treat namedtuple instances as tuples + # see: https://github.com/python/cpython/issues/52044 + elif isinstance(node, tuple) and not hasattr(node, "_fields"): result = _handle_immutable_sequence(node, json_id) elif isinstance(node, (list, lazy_nodes.AsdfListNode)): result = _handle_mutable_sequence(node, json_id) diff --git a/asdf/util.py b/asdf/util.py index b099213bc..c03b458b1 100644 --- a/asdf/util.py +++ b/asdf/util.py @@ -5,17 +5,12 @@ import re import struct import sys -import types -import warnings from functools import lru_cache -from importlib import metadata -from urllib.request import pathname2url import numpy as np import yaml -from packaging.version import Version -from . import constants, exceptions +from . import constants # The standard library importlib.metadata returns duplicate entrypoints # for all python versions up to and including 3.11 @@ -23,9 +18,9 @@ # see PR https://github.com/asdf-format/asdf/pull/1260 # see issue https://github.com/asdf-format/asdf/issues/1254 if sys.version_info >= (3, 12): - from importlib.metadata import packages_distributions + pass else: - from importlib_metadata import packages_distributions + pass # We're importing our own copy of urllib.parse because @@ -46,15 +41,10 @@ __all__ = [ "load_yaml", - "human_list", "get_array_base", "get_base_uri", - "filepath_to_url", - "iter_subclasses", "calculate_padding", - "resolve_name", "NotSet", - "is_primitive", "uri_match", "get_class_name", "get_file_type", @@ -106,35 +96,6 @@ def load_yaml(init, tagged=False): return content -def human_list(line, separator="and"): - """ - Formats a list for human readability. - - Parameters - ---------- - l : sequence - A sequence of strings - - separator : string, optional - The word to use between the last two entries. Default: - ``"and"``. - - Returns - ------- - formatted_list : string - - Examples - -------- - >>> human_list(["vanilla", "strawberry", "chocolate"], "or") # doctest: +SKIP - 'vanilla, strawberry or chocolate' - """ - warnings.warn("asdf.util.human_list is deprecated", exceptions.AsdfDeprecationWarning) - if len(line) == 1: - return line[0] - - return ", ".join(line[:-1]) + " " + separator + " " + line[-1] - - def get_array_base(arr): """ For a given Numpy array, finds the base array that "owns" the @@ -156,15 +117,6 @@ def get_base_uri(uri): return _patched_urllib_parse.urlunparse([*list(parts[:5]), ""]) -def filepath_to_url(path): - """ - For a given local file path, return a file:// url. - """ - msg = "asdf.util.filepath_to_url is deprecated. Please use pathlib.Path.as_uri" - warnings.warn(msg, exceptions.AsdfDeprecationWarning) - return _patched_urllib_parse.urljoin("file:", pathname2url(path)) - - def _iter_subclasses(cls): """ Returns all subclasses of a class. @@ -174,14 +126,6 @@ def _iter_subclasses(cls): yield from _iter_subclasses(x) -def iter_subclasses(cls): - """ - Returns all subclasses of a class. - """ - warnings.warn("asdf.util.iter_subclasses is deprecated", exceptions.AsdfDeprecationWarning) - yield from _iter_subclasses(cls) - - def calculate_padding(content_size, pad_blocks, block_size): """ Calculates the amount of extra space to add to a block given the @@ -313,72 +257,6 @@ def __hash__(self): return hash(frozenset(self.items())) -def resolve_name(name): - """Resolve a name like ``module.object`` to an object and return it. - - This ends up working like ``from module import object`` but is easier - to deal with than the `__import__` builtin and supports digging into - submodules. - - Parameters - ---------- - - name : `str` - A dotted path to a Python object--that is, the name of a function, - class, or other object in a module with the full path to that module, - including parent modules, separated by dots. Also known as the fully - qualified name of the object. - - Examples - -------- - - >>> resolve_name('asdf.util.resolve_name') # doctest: +SKIP - - - Raises - ------ - `ImportError` - If the module or named object is not found. - """ - - warnings.warn( - "asdf.util.resolve_name is deprecated, see astropy.utils.resolve_name", exceptions.AsdfDeprecationWarning - ) - - # Note: On python 2 these must be str objects and not unicode - parts = [str(part) for part in name.split(".")] - - if len(parts) == 1: - # No dots in the name--just a straight up module import - cursor = 1 - attr_name = "" # Must not be unicode on Python 2 - else: - cursor = len(parts) - 1 - attr_name = parts[-1] - - module_name = parts[:cursor] - - while cursor > 0: - try: - ret = __import__(str(".".join(module_name)), fromlist=[attr_name]) - break - except ImportError: - if cursor == 0: - raise - cursor -= 1 - module_name = parts[:cursor] - attr_name = parts[cursor] - ret = "" - - for part in parts[cursor:]: - try: - ret = getattr(ret, part) - except AttributeError as err: - raise ImportError(name) from err - - return ret - - def get_class_name(obj, instance=True): """ Given a class or instance of a class, returns a string representing the @@ -396,65 +274,6 @@ def get_class_name(obj, instance=True): return f"{typ.__module__}.{typ.__qualname__}" -def minversion(module, version, inclusive=True): - """ - Returns `True` if the specified Python module satisfies a minimum version - requirement, and `False` if not. - - Copied from astropy.utils.misc.minversion to avoid dependency on astropy. - - Parameters - ---------- - - module : module or `str` - An imported module of which to check the version, or the name of - that module (in which case an import of that module is attempted-- - if this fails `False` is returned). - - version : `str` - The version as a string that this module must have at a minimum (e.g. - ``'0.12'``). - - inclusive : `bool` - The specified version meets the requirement inclusively (i.e. ``>=``) - as opposed to strictly greater than (default: `True`). - """ - - warnings.warn("asdf.util.minversion is deprecated, see astropy.utils.minversion", exceptions.AsdfDeprecationWarning) - - if isinstance(module, types.ModuleType): - module_name = module.__name__ - module_version = getattr(module, "__version__", None) - elif isinstance(module, str): - module_name = module - module_version = None - try: - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "asdf.util.resolve_name", exceptions.AsdfDeprecationWarning) - module = resolve_name(module_name) - except ImportError: - return False - else: - msg = f"module argument must be an actual imported module, or the import name of the module; got {module!r}" - raise ValueError(msg) - - if module_version is None: - try: - module_version = metadata.version(module_name) - except metadata.PackageNotFoundError: - # Maybe the distribution name is different from package name. - # Calling packages_distributions is costly so we do it only - # if necessary, as only a few packages don't have the same - # distribution name. - dist_names = packages_distributions() - module_version = metadata.version(dist_names[module_name][0]) - - if inclusive: - return Version(module_version) >= Version(version) - - return Version(module_version) > Version(version) - - class _InheritDocstrings(type): """ This metaclass makes methods of a class automatically have their @@ -508,24 +327,6 @@ def __repr__(self): NotSet = _NotSetType() -def is_primitive(value): - """ - Determine if a value is an instance of a "primitive" type. - - Parameters - ---------- - value : object - the value to test - - Returns - ------- - bool - True if the value is primitive, False otherwise - """ - warnings.warn("asdf.util.is_primitive is deprecated", exceptions.AsdfDeprecationWarning) - return isinstance(value, (bool, int, float, complex, str)) or value is None - - def uri_match(pattern, uri): """ Determine if a URI matches a URI pattern with possible diff --git a/asdf/versioning.py b/asdf/versioning.py index f6f068870..160c0f62d 100644 --- a/asdf/versioning.py +++ b/asdf/versioning.py @@ -3,18 +3,15 @@ of the ASDF spec. """ -import warnings from functools import total_ordering import yaml from semantic_version import SimpleSpec, Version -from .exceptions import AsdfDeprecationWarning - _yaml_base_loader = yaml.CSafeLoader if getattr(yaml, "__with_libyaml__", None) else yaml.SafeLoader -__all__ = ["AsdfVersion", "AsdfSpec", "AsdfVersionMixin", "split_tag_version", "join_tag_version"] +__all__ = ["AsdfVersion", "AsdfVersionMixin", "split_tag_version", "join_tag_version"] def split_tag_version(tag): @@ -33,34 +30,6 @@ def join_tag_version(name, version): return f"{name}-{version}" -_version_map = {} - - -def _get_version_map(version): - version_map = _version_map.get(version) - - if version_map is None: - from .config import get_config - - uri = f"http://stsci.edu/schemas/asdf/version_map-{version}" - # The following call to yaml.load is safe because we're - # using a loader that inherits from pyyaml's SafeLoader. - version_map = yaml.load(get_config().resource_manager[uri], Loader=_yaml_base_loader) # noqa: S506 - - # Separate the core tags from the rest of the standard for convenience - version_map["core"] = {} - version_map["standard"] = {} - for tag_name, tag_version in version_map["tags"].items(): - if tag_name.startswith("tag:stsci.edu:asdf/core"): - version_map["core"][tag_name] = tag_version - else: - version_map["standard"][tag_name] = tag_version - - _version_map[version] = version_map - - return version_map - - @total_ordering class AsdfVersionMixin: """This mix-in is required in order to impose the total ordering that we @@ -114,43 +83,6 @@ def __init__(self, version): super().__init__(version) -class AsdfSpec(SimpleSpec): - """ - Deprecated. - """ - - def __init__(self, *args, **kwargs): - warnings.warn("AsdfSpec is deprecated.", AsdfDeprecationWarning) - super().__init__(*args, **kwargs) - - def match(self, version): - if isinstance(version, (str, tuple, list)): - version = AsdfVersion(version) - return super().match(version) - - def __iterate_versions(self, versions): - for v in versions: - yield AsdfVersion(v) if isinstance(v, (str, tuple, list)) else v - - def select(self, versions): - return super().select(self.__iterate_versions(versions)) - - def filter(self, versions): - return super().filter(self.__iterate_versions(versions)) - - def __eq__(self, other): - """Equality between Spec and Version, string, or tuple, means match""" - if isinstance(other, SimpleSpec): - return super().__eq__(other) - return self.match(other) - - def __ne__(self, other): - return not self.__eq__(other) - - def __hash__(self): - return super().__hash__() - - supported_versions = [ AsdfVersion("1.0.0"), AsdfVersion("1.1.0"), diff --git a/asdf/yamlutil.py b/asdf/yamlutil.py index 718bfecc2..5615f4b8b 100644 --- a/asdf/yamlutil.py +++ b/asdf/yamlutil.py @@ -318,7 +318,6 @@ def _walker(obj): return treeutil.walk_and_modify( tree, _walker, - ignore_implicit_conversion=ctx._ignore_implicit_conversion, # Walk the tree in preorder, so that extensions can return # container nodes with unserialized children. postorder=False, @@ -362,7 +361,6 @@ def _walker(node): return treeutil.walk_and_modify( tree, _walker, - ignore_implicit_conversion=ctx._ignore_implicit_conversion, # Walk the tree in postorder, so that extensions receive # container nodes with children already deserialized. postorder=True, diff --git a/changes/1852.removal.rst b/changes/1852.removal.rst new file mode 100644 index 000000000..70b38712d --- /dev/null +++ b/changes/1852.removal.rst @@ -0,0 +1 @@ +Remove deprecated API. See docs for full details. diff --git a/docs/asdf/whats_new.rst b/docs/asdf/whats_new.rst index cad440937..8f9328cbf 100644 --- a/docs/asdf/whats_new.rst +++ b/docs/asdf/whats_new.rst @@ -6,7 +6,93 @@ What's New ********** -.. _whats_new_3.0.0: +.. _whats_new_4.0.0: + +4.0.0 +===== + +Hi! Asdf 4.0.0 is a new major version including: + +- :ref:`removal of deprecated API ` +- :ref:`changes to a few key defaults ` + +.. _whats_new_4.0.0_removed: + +Removed API +----------- + +- The ``copy_arrays`` argument for ``asdf.open`` and ``AsdfFile`` has been removed + and replaced by ``memmap`` (``memmap == not copy_arrays``). +- ``ignore_version_mismatch`` has had no effect since asdf 3.0.0 and was removed. +- the `asdf.util` submodule had several unused functions removed: + - ``filepath_to_url``, see ``pathlib.Path.as_uri`` as an alternative + - ``is_primitive``, use ``isinstance`` + - ``iter_subclasses``, use ``object.__subclasses__`` + - ``minversion``, see ``astropy.utils.minversion`` + - ``resolve_name``, see ``astropy.utils.resolve_name`` + - ``human_list``, use ``pprint`` or your own string formatting +- ``versioning.AsdfSpec``, see `asdf.versioning.AsdfVersion` comparisons +- ``asdf.testing.helpers.format_tag``, use your own string formatting +- ``AsdfFile.version_map``, could have been removed with the legacy extension API +- ``AsdfFile.resolve_and_inline``, use `AsdfFile.resolve_references` and ``all_array_storage=="inline"`` +- ``asdf.asdf``, the public items in this submodule are all in the top level `asdf` module +- ``asdf.asdf.SerializationContext``, available at `asdf.extension.SerializationContext` +- ``asdf.stream``, see `asdf.tags.core.Stream` +- ``ignore_implicit_conversion`` has been removed (see :ref:`whats_new_4.0.0_implicit_conversion` below) +- providing a tag uri within a schema ``$ref`` will no longer resolve to the schema uri associated with that tag + +.. _whats_new_4.0.0_defaults: + +New Defaults +------------ + +.. _whats_new_4.0.0_validation: + +Validation +^^^^^^^^^^ + +Several operations no longer automatically trigger tree validation. +These changes were made to limit the number of times a tree is validated +to allow incremental construction of trees and to improve performance. + +- providing a tree to ``AsdfFile.__init__`` no longer triggers validation +- calling `AsdfFile.resolve_references` no longer triggers validation +- assigning a new tree to `AsdfFile.tree` no longer triggers validation + +.. note:: + + Validation can be triggered with `AsdfFile.validate` and will + occur when writing to a file (or reading if ``AsdfConfig.validate_on_read`` + is enabled). + +.. _whats_new_4.0.0_find_references: + +Find References +^^^^^^^^^^^^^^^ + +Similar to :ref:`whats_new_4.0.0_validation` several operations no longer +automatically trigger `AsdfFile.find_references`: + +- `asdf.open` does not trigger `AsdfFile.find_references` +- providing a tree (or `AsdfFile`) to ``AsdfFile.__init__`` no longer triggers `AsdfFile.find_references` + +.. note:: + + `AsdfFile.find_references` is only for JSON pointer references + which are most useful for external references. YAML anchors and + aliases are automatically resolved. + +.. _whats_new_4.0.0_implicit_conversion: + +Implicit Conversion +^^^^^^^^^^^^^^^^^^^ + +In older asdf versions ``namedtuple`` instances were automatically +converted to lists when written to a file. When read back in the +``namedtuple`` was not reconstructed and instead these objects were +returned as lists. With asdf 4.0.0 this "implicit conversion" is +no longer performed which allows extensions to implement converters +for ``namedtuple`` instances. 3.0.0 ===== @@ -28,7 +114,7 @@ The following deprecated features are removed in asdf 3.0.0: Please see the links above or the :ref:`deprecations` for more details. -.. _whats_new_3.0.0__ew_features: +.. _whats_new_3.0.0__new_features: New features ------------ diff --git a/pytest_asdf/plugin.py b/pytest_asdf/plugin.py index 6f5e60e7a..d1f5b5dee 100644 --- a/pytest_asdf/plugin.py +++ b/pytest_asdf/plugin.py @@ -1,7 +1,6 @@ import io import os import pathlib -import warnings from dataclasses import dataclass import numpy as np @@ -41,12 +40,6 @@ def pytest_addoption(parser): type="bool", default=False, ) - parser.addini( - "asdf_schema_ignore_version_mismatch", - "Set to true to disable warnings when missing explicit support for a tag", - type="string", - default="", - ) parser.addoption("--asdf-tests", action="store_true", help="Enable ASDF schema tests") @@ -282,14 +275,6 @@ def pytest_collect_file(file_path, parent): skip_examples = parent.config.getini("asdf_schema_skip_examples") validate_default = parent.config.getini("asdf_schema_validate_default") ignore_unrecognized_tag = parent.config.getini("asdf_schema_ignore_unrecognized_tag") - ignore_version_mismatch = parent.config.getini("asdf_schema_ignore_version_mismatch") - if ignore_version_mismatch != "": - from asdf.exceptions import AsdfDeprecationWarning - - warnings.warn( - "asdf_schema_ignore_version_mismatch is deprecated and has done nothing since asdf 3.0.0", - AsdfDeprecationWarning, - ) skip_tests = _parse_test_list(parent.config.getini("asdf_schema_skip_tests")) xfail_tests = _parse_test_list(parent.config.getini("asdf_schema_xfail_tests"))