diff --git a/README.md b/README.md index 0c49e0f..9539620 100644 --- a/README.md +++ b/README.md @@ -88,12 +88,13 @@ from asdf.extension import Extension from asdf_pydantic.converter import AsdfPydanticConverter from mypackage.shapes import Rectangle -AsdfPydanticConverter.add_models(Rectangle) +converter = AsdfPydanticConverter() +converter.add_models(Rectangle) class ShapesExtension(Extension): extension_uri = "asdf://asdf-pydantic/examples/extensions/shapes-1.0.0" - converters = [AsdfPydanticConverter()] - tags = [*AsdfPydanticConverter().tags] + converters = [converter] + tags = [*converter.tags] ``` Install the extension either by entry point specification or add it to diff --git a/asdf_pydantic/converter.py b/asdf_pydantic/converter.py index 7100044..4be2684 100644 --- a/asdf_pydantic/converter.py +++ b/asdf_pydantic/converter.py @@ -1,37 +1,29 @@ from __future__ import annotations -from typing import Optional, Type +from typing import Type from asdf.extension import Converter from asdf_pydantic.model import AsdfPydanticModel -_ASDF_PYDANTIC_SINGLETON_CONVERTER: Optional[AsdfPydanticConverter] = None - class AsdfPydanticConverter(Converter): - """Implements a converter compatible with all subclass of AsdfPydanticModel. - - The instance is a singleton. - """ - - _tag_to_class: dict[str, Type[AsdfPydanticModel]] = {} + """Implements a converter compatible with all subclass of AsdfPydanticModel.""" - def __init__(self) -> None: - global _ASDF_PYDANTIC_SINGLETON_CONVERTER + _tag_to_class: dict[str, Type[AsdfPydanticModel]] - if _ASDF_PYDANTIC_SINGLETON_CONVERTER is None: - _ASDF_PYDANTIC_SINGLETON_CONVERTER = self + def __init__(self, *model_classes: Type[AsdfPydanticModel]) -> None: + self._tag_to_class = {} + self.add_models(*model_classes) + super().__init__() - self = _ASDF_PYDANTIC_SINGLETON_CONVERTER - - @classmethod def add_models( - cls, *model_classes: Type[AsdfPydanticModel] + self, *model_classes: Type[AsdfPydanticModel] ) -> "AsdfPydanticConverter": for model_class in model_classes: - cls._tag_to_class[model_class.get_tag_uri()] = model_class - return cls() + self._tag_to_class[model_class.get_tag_uri()] = model_class + + return self @property def tags(self) -> tuple[str]: diff --git a/tests/examples/test_astropy_tables.py b/tests/examples/test_astropy_tables.py index d90bd4a..c64ae05 100644 --- a/tests/examples/test_astropy_tables.py +++ b/tests/examples/test_astropy_tables.py @@ -24,13 +24,14 @@ class Database(AsdfPydanticModel): @pytest.fixture() def asdf_extension(): """Registers an ASDF extension containing models for this test.""" - AsdfPydanticConverter.add_models(Database) + converter = AsdfPydanticConverter() + converter.add_models(Database) class TestExtension(Extension): extension_uri = "asdf://asdf-pydantic/examples/extensions/test-1.0.0" - converters = [AsdfPydanticConverter()] # type: ignore - tags = [*AsdfPydanticConverter().tags] # type: ignore + converters = [converter] # type: ignore + tags = [*converter.tags] # type: ignore asdf.get_config().add_extension(TestExtension()) diff --git a/tests/examples/test_node.py b/tests/examples/test_node.py index 09cdb6d..5408af8 100644 --- a/tests/examples/test_node.py +++ b/tests/examples/test_node.py @@ -54,12 +54,13 @@ class AsdfNode(AsdfPydanticModel): @pytest.fixture() def asdf_extension(): """Registers an ASDF extension containing models for this test.""" - AsdfPydanticConverter.add_models(AsdfNode) + converter = AsdfPydanticConverter() + converter.add_models(AsdfNode) class TestExtension(Extension): extension_uri = "asdf://asdf-pydantic/examples/extensions/test-1.0.0" - converters = [AsdfPydanticConverter()] # type: ignore + converters = [converter] # type: ignore tags = [AsdfNode.get_tag_definition()] # type: ignore with asdf.config_context() as asdf_config: diff --git a/tests/examples/test_rectangle.py b/tests/examples/test_rectangle.py index 9d414d7..793a9fe 100644 --- a/tests/examples/test_rectangle.py +++ b/tests/examples/test_rectangle.py @@ -14,12 +14,13 @@ @pytest.fixture() def asdf_extension(): """Registers an ASDF extension containing models for this test.""" - AsdfPydanticConverter.add_models(AsdfRectangle) + converter = AsdfPydanticConverter() + converter.add_models(AsdfRectangle) class TestExtension(Extension): extension_uri = "asdf://asdf-pydantic/examples/extensions/test-1.0.0" - converters = [AsdfPydanticConverter()] # type: ignore + converters = [converter] # type: ignore tags = [AsdfRectangle.get_tag_definition()] # type: ignore with asdf.config_context() as asdf_config: diff --git a/tests/patterns/astropy_types_test.py b/tests/patterns/astropy_types_test.py index 4c35af4..4106ee4 100644 --- a/tests/patterns/astropy_types_test.py +++ b/tests/patterns/astropy_types_test.py @@ -23,13 +23,14 @@ class DataContainer(AsdfPydanticModel): def setup_module(): - AsdfPydanticConverter.add_models(DataPoint, DataContainer) + converter = AsdfPydanticConverter() + converter.add_models(DataPoint, DataContainer) class TestExtension(Extension): extension_uri = "asdf://asdf-pydantic/examples/extensions/test-1.0.0" - converters = [AsdfPydanticConverter()] # type: ignore - tags = [*AsdfPydanticConverter().tags] # type: ignore + converters = [converter] # type: ignore + tags = [*converter.tags] # type: ignore asdf.get_config().add_extension(TestExtension()) diff --git a/tests/patterns/union_type_test.py b/tests/patterns/union_type_test.py index f10d27c..98f1da5 100644 --- a/tests/patterns/union_type_test.py +++ b/tests/patterns/union_type_test.py @@ -20,13 +20,14 @@ class UnionObject(AsdfPydanticModel): def setup_module(): - AsdfPydanticConverter.add_models(UnionObject) + converter = AsdfPydanticConverter() + converter.add_models(UnionObject) class TestExtension(Extension): extension_uri = "asdf://asdf-pydantic/examples/extensions/test-1.0.0" - converters = [AsdfPydanticConverter()] # type: ignore - tags = [*AsdfPydanticConverter().tags] # type: ignore + converters = [converter] # type: ignore + tags = [*converter.tags] # type: ignore asdf.get_config().add_extension(TestExtension()) diff --git a/tests/schema_validation_test.py b/tests/schema_validation_test.py index 60a3f09..2508462 100644 --- a/tests/schema_validation_test.py +++ b/tests/schema_validation_test.py @@ -14,13 +14,14 @@ def setup_module(): - AsdfPydanticConverter.add_models(AsdfRectangle) + converter = AsdfPydanticConverter() + converter.add_models(AsdfRectangle) class TestExtension(Extension): extension_uri = "asdf://asdf-pydantic/examples/extensions/test-1.0.0" # type: ignore - tags = [*AsdfPydanticConverter().tags] # type: ignore - converters = [AsdfPydanticConverter()] # type: ignore + tags = [*converter.tags] # type: ignore + converters = [converter] # type: ignore # HACK: The schema URI should be referenced from `AsdfRectangle._schema`. # Then there should be a way to automatically add the schema to ASDF diff --git a/tests/test_converter.py b/tests/test_converter.py new file mode 100644 index 0000000..5421296 --- /dev/null +++ b/tests/test_converter.py @@ -0,0 +1,13 @@ +import pytest + +from asdf_pydantic.converter import AsdfPydanticConverter +from asdf_pydantic.model import AsdfPydanticModel + + +class TestModel(AsdfPydanticModel): + _tag = "https://example.org/test_model" + + +@pytest.mark.parametrize("args", [tuple(), (TestModel,)]) +def test_converter_is_unscoped_by_default(args): + assert AsdfPydanticConverter(*args) is not AsdfPydanticConverter(*args)