From 4cd53c4aab9455937823a4c874ebcc0c1837661c Mon Sep 17 00:00:00 2001 From: jdoiro3 Date: Mon, 22 May 2023 08:41:50 -0400 Subject: [PATCH 1/9] allow typing_extensions.Annotated to be used when version is less than 3.9 --- src/cattrs/_compat.py | 5 +++-- tests/test_converter.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/cattrs/_compat.py b/src/cattrs/_compat.py index 18106eff..d358031e 100644 --- a/src/cattrs/_compat.py +++ b/src/cattrs/_compat.py @@ -143,9 +143,10 @@ def get_final_base(type) -> Optional[type]: from collections import Counter as ColCounter from typing import Counter, Union, _GenericAlias + from typing_extensions import Annotated, get_origin - def is_annotated(_): - return False + def is_annotated(type) -> bool: + return get_origin(type) == Annotated def is_tuple(type): return type in (Tuple, tuple) or ( diff --git a/tests/test_converter.py b/tests/test_converter.py index fc441017..70f8c733 100644 --- a/tests/test_converter.py +++ b/tests/test_converter.py @@ -596,3 +596,37 @@ class Outer: structured = converter.structure(raw, Outer) assert structured == Outer(Inner(2), [Inner(2)]) + + +def test_annotated_with_typing_extensions_attrs(): + """Annotation support works for attrs classes.""" + from typing_extensions import Annotated + + converter = Converter() + + @attr.define + class Inner: + a: int + + @attr.define + class Outer: + i: Annotated[Inner, "test"] # noqa + j: list[Annotated[Inner, "test"]] # noqa + + orig = Outer(Inner(1), [Inner(1)]) + raw = converter.unstructure(orig) + + assert raw == {"i": {"a": 1}, "j": [{"a": 1}]} + + structured = converter.structure(raw, Outer) + assert structured == orig + + # Now register a hook and rerun the test. + converter.register_unstructure_hook(Inner, lambda v: {"a": 2}) + + raw = converter.unstructure(Outer(Inner(1), [Inner(1)])) + + assert raw == {"i": {"a": 2}, "j": [{"a": 2}]} + + structured = converter.structure(raw, Outer) + assert structured == Outer(Inner(2), [Inner(2)]) From 9342be400f3faa5275ebb047b9bfbceef72223e6 Mon Sep 17 00:00:00 2001 From: jdoiro3 Date: Mon, 22 May 2023 09:02:15 -0400 Subject: [PATCH 2/9] looks like we need this type fix for older versions of python --- tests/test_converter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_converter.py b/tests/test_converter.py index 70f8c733..1127a492 100644 --- a/tests/test_converter.py +++ b/tests/test_converter.py @@ -601,6 +601,7 @@ class Outer: def test_annotated_with_typing_extensions_attrs(): """Annotation support works for attrs classes.""" from typing_extensions import Annotated + from typing import List converter = Converter() @@ -611,7 +612,7 @@ class Inner: @attr.define class Outer: i: Annotated[Inner, "test"] # noqa - j: list[Annotated[Inner, "test"]] # noqa + j: List[Annotated[Inner, "test"]] # noqa orig = Outer(Inner(1), [Inner(1)]) raw = converter.unstructure(orig) From e0fdfd911f04bf3e3326b0a3dbfa67cf54028cad Mon Sep 17 00:00:00 2001 From: jdoiro3 Date: Mon, 22 May 2023 09:14:30 -0400 Subject: [PATCH 3/9] added entry for PR; updated docs on contributing --- CONTRIBUTING.md | 2 +- HISTORY.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e8ebc7fa..78e37aaf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -59,7 +59,7 @@ $ git clone git@github.com:your_name_here/cattrs.git ```shell $ cd cattrs/ -$ poetry install +$ poetry install --all-extras ``` 4. Create a branch for local development:: diff --git a/HISTORY.md b/HISTORY.md index 294f12c8..01f6d3a4 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -18,6 +18,7 @@ ([#350](https://github.com/python-attrs/cattrs/issues/350) [#353](https://github.com/python-attrs/cattrs/pull/353)) - Subclasses structuring and unstructuring is now supported via a custom `include_subclasses` strategy. ([#312](https://github.com/python-attrs/cattrs/pull/312)) +- Adds support for `typing_extensions.Annotated` when the python version is less than `3.9`. ([#366](https://github.com/python-attrs/cattrs/pull/366)) ## 22.2.0 (2022-10-03) From c4e7b846b9d256405dc401f8216f3e4ca83a7687 Mon Sep 17 00:00:00 2001 From: jdoiro3 Date: Mon, 22 May 2023 13:11:21 -0400 Subject: [PATCH 4/9] simplified expression --- src/cattrs/_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cattrs/_compat.py b/src/cattrs/_compat.py index d358031e..d65b3ae5 100644 --- a/src/cattrs/_compat.py +++ b/src/cattrs/_compat.py @@ -146,7 +146,7 @@ def get_final_base(type) -> Optional[type]: from typing_extensions import Annotated, get_origin def is_annotated(type) -> bool: - return get_origin(type) == Annotated + return get_origin(type) is Annotated def is_tuple(type): return type in (Tuple, tuple) or ( From d416187fd9bd95971537bd82c414f1f255988792 Mon Sep 17 00:00:00 2001 From: jdoiro3 Date: Mon, 22 May 2023 16:16:39 -0400 Subject: [PATCH 5/9] tweak docs --- HISTORY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index f23f13d2..f2500f54 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -20,7 +20,7 @@ ([#350](https://github.com/python-attrs/cattrs/issues/350) [#353](https://github.com/python-attrs/cattrs/pull/353)) - Subclasses structuring and unstructuring is now supported via a custom `include_subclasses` strategy. ([#312](https://github.com/python-attrs/cattrs/pull/312)) -- Adds support for `typing_extensions.Annotated` when the python version is less than `3.9`. ([#366](https://github.com/python-attrs/cattrs/pull/366)) +- Add support for `typing_extensions.Annotated` when the python version is less than `3.9`. ([#366](https://github.com/python-attrs/cattrs/pull/366)) - Add unstructuring and structuring support to `deque` in standard lib. ([#355](https://github.com/python-attrs/cattrs/issues/355)) From 29379f492acb2938eae61556fedb0c5f5f3fb912 Mon Sep 17 00:00:00 2001 From: jdoiro3 Date: Mon, 22 May 2023 16:18:43 -0400 Subject: [PATCH 6/9] removed merge text --- HISTORY.md | 1 - 1 file changed, 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 2c38de1b..743022a8 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -20,7 +20,6 @@ ([#350](https://github.com/python-attrs/cattrs/issues/350) [#353](https://github.com/python-attrs/cattrs/pull/353)) - Subclasses structuring and unstructuring is now supported via a custom `include_subclasses` strategy. ([#312](https://github.com/python-attrs/cattrs/pull/312)) -<<<<<<< HEAD - Add support for `typing_extensions.Annotated` when the python version is less than `3.9`. ([#366](https://github.com/python-attrs/cattrs/pull/366)) - Add unstructuring and structuring support for the standard library `deque`. ([#355](https://github.com/python-attrs/cattrs/pull/355)) From 82ff040deb9844393179dcfca859e8b57344188e Mon Sep 17 00:00:00 2001 From: jdoiro3 Date: Tue, 23 May 2023 07:04:14 -0400 Subject: [PATCH 7/9] created alias for duplicated function name --- src/cattrs/_compat.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cattrs/_compat.py b/src/cattrs/_compat.py index 8f5ece41..ee8f0e20 100644 --- a/src/cattrs/_compat.py +++ b/src/cattrs/_compat.py @@ -174,7 +174,8 @@ def get_final_base(type) -> Optional[type]: from collections import Counter as ColCounter from typing import Counter, Union, _GenericAlias - from typing_extensions import Annotated, get_origin, NotRequired, Required + from typing_extensions import Annotated, NotRequired, Required + from typing_extensions import get_origin as te_get_origin if is_py38: from typing import TypedDict, _TypedDictMeta @@ -183,7 +184,7 @@ def get_final_base(type) -> Optional[type]: TypedDict = ExtensionsTypedDict def is_annotated(type) -> bool: - return get_origin(type) is Annotated + return te_get_origin(type) is Annotated def is_tuple(type): return type in (Tuple, tuple) or ( From 9a5aa3efd2c744b9aee7624112ecb08f3cd20741 Mon Sep 17 00:00:00 2001 From: jdoiro3 Date: Tue, 23 May 2023 07:15:06 -0400 Subject: [PATCH 8/9] typing and typing_ext seem to have the same implementation for get_origin --- src/cattrs/_compat.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cattrs/_compat.py b/src/cattrs/_compat.py index ee8f0e20..2f491731 100644 --- a/src/cattrs/_compat.py +++ b/src/cattrs/_compat.py @@ -175,7 +175,6 @@ def get_final_base(type) -> Optional[type]: from collections import Counter as ColCounter from typing import Counter, Union, _GenericAlias from typing_extensions import Annotated, NotRequired, Required - from typing_extensions import get_origin as te_get_origin if is_py38: from typing import TypedDict, _TypedDictMeta @@ -184,7 +183,7 @@ def get_final_base(type) -> Optional[type]: TypedDict = ExtensionsTypedDict def is_annotated(type) -> bool: - return te_get_origin(type) is Annotated + return get_origin(type) is Annotated def is_tuple(type): return type in (Tuple, tuple) or ( From cf97e3cae2294b128c2347e415977b394a17d2c7 Mon Sep 17 00:00:00 2001 From: jdoiro3 Date: Tue, 23 May 2023 07:19:20 -0400 Subject: [PATCH 9/9] Revert "typing and typing_ext seem to have the same implementation for get_origin" This reverts commit 9a5aa3efd2c744b9aee7624112ecb08f3cd20741. --- src/cattrs/_compat.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cattrs/_compat.py b/src/cattrs/_compat.py index 2f491731..ee8f0e20 100644 --- a/src/cattrs/_compat.py +++ b/src/cattrs/_compat.py @@ -175,6 +175,7 @@ def get_final_base(type) -> Optional[type]: from collections import Counter as ColCounter from typing import Counter, Union, _GenericAlias from typing_extensions import Annotated, NotRequired, Required + from typing_extensions import get_origin as te_get_origin if is_py38: from typing import TypedDict, _TypedDictMeta @@ -183,7 +184,7 @@ def get_final_base(type) -> Optional[type]: TypedDict = ExtensionsTypedDict def is_annotated(type) -> bool: - return get_origin(type) is Annotated + return te_get_origin(type) is Annotated def is_tuple(type): return type in (Tuple, tuple) or (