From 8174d3a634c0945683115bf96890acc9dec39f69 Mon Sep 17 00:00:00 2001 From: Brian Pugh Date: Wed, 20 Sep 2023 22:55:41 -0700 Subject: [PATCH] fix config-passing issues with attrs library. --- autoregistry/_registry.py | 28 +++++++++++++++++----------- pyproject.toml | 1 + tests/test_attrs.py | 20 ++++++++++++++++++++ 3 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 tests/test_attrs.py diff --git a/autoregistry/_registry.py b/autoregistry/_registry.py index 759ffeb..c2515cd 100644 --- a/autoregistry/_registry.py +++ b/autoregistry/_registry.py @@ -203,18 +203,24 @@ def __new__( # that hooks like __init_subclass__ have appropriately set registry attributes. # Each subclass gets its own registry. - # Copy the nearest parent config, then update it with new params - for parent_cls in bases: - try: - registry_config = parent_cls.__registry__.config.copy() - break - except AttributeError: - pass + # Copy the nearest parent config, then update it with new params. + # Some class construction libraries, like ``attrs``, will recreate a class. + # In these situations, the old-class will have it's attributes (like the __registry__ + # object) passed in via the ``namespace``. + if "__registry__" in namespace: + registry_config = namespace["__registry__"].config else: - # No parent config, create a new one from scratch. - namespace["__registry__"] = _Registry(RegistryConfig(**config)) - new_cls = super().__new__(cls, cls_name, bases, namespace) - return new_cls + for parent_cls in bases: + try: + registry_config = parent_cls.__registry__.config.copy() + break + except AttributeError: + pass + else: + # No parent config, create a new one from scratch. + namespace["__registry__"] = _Registry(RegistryConfig(**config)) + new_cls = super().__new__(cls, cls_name, bases, namespace) + return new_cls # Derive registry name before updating registry config, since a classes own name is # subject to it's parents configuration, not its own. diff --git a/pyproject.toml b/pyproject.toml index 591e9a6..5266307 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,6 +34,7 @@ pytest-cov = ">=3,<5" pytest-mock = "^3.7.0" pyright = "^1.1.273" pytest-pyright = "^0.0.3" +attrs = "^23.1.0" [tool.coverage.run] branch = true diff --git a/tests/test_attrs.py b/tests/test_attrs.py new file mode 100644 index 0000000..96f7191 --- /dev/null +++ b/tests/test_attrs.py @@ -0,0 +1,20 @@ +from attrs import frozen + +from autoregistry import Registry + + +def test_attrs_compatability(): + @frozen + class Media(Registry, snake_case=True): + name: str + year: int + + class Movie(Media): + pass + + class MusicVideo(Media): + pass + + assert list(Media) == ["movie", "music_video"] + assert Media["movie"] == Movie + assert Media["music_video"] == MusicVideo