Skip to content

Commit

Permalink
Allows use of typing_extensions.Annotated when python version is le…
Browse files Browse the repository at this point in the history
…ss than `3.9` (#366)

* allow typing_extensions.Annotated to be used when version is less than 3.9

* looks like we need this type fix for older versions of python

* added entry for PR; updated docs on contributing

* simplified expression

* tweak docs

* removed merge text

* created alias for duplicated function name

* typing and typing_ext seem to have the same implementation for get_origin

* Revert "typing and typing_ext seem to have the same implementation for get_origin"

This reverts commit 9a5aa3e.
  • Loading branch information
jdoiro3 authored May 23, 2023
1 parent ba5ccb2 commit 67bc98e
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 5 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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::
Expand Down
1 change: 1 addition & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +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))
- 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))

Expand Down
8 changes: 4 additions & 4 deletions src/cattrs/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,17 +174,17 @@ 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
else:
_TypedDictMeta = None
TypedDict = ExtensionsTypedDict

from typing_extensions import NotRequired, Required

def is_annotated(_):
return False
def is_annotated(type) -> bool:
return te_get_origin(type) is Annotated

def is_tuple(type):
return type in (Tuple, tuple) or (
Expand Down
35 changes: 35 additions & 0 deletions tests/test_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -653,3 +653,38 @@ 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
from typing import List

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)])

0 comments on commit 67bc98e

Please sign in to comment.