Skip to content

Commit

Permalink
Merge branch 'main' into tuple-keys
Browse files Browse the repository at this point in the history
  • Loading branch information
hynek committed Dec 15, 2021
2 parents 99b0acc + bd0d0cc commit 956a8d3
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 13 deletions.
21 changes: 12 additions & 9 deletions docs/examples.rst
Expand Up @@ -199,7 +199,6 @@ For that, `attr.asdict` offers a callback that decides whether an attribute shou

.. doctest::

>>> from typing import List
>>> from attr import asdict

>>> @define
Expand All @@ -209,7 +208,7 @@ For that, `attr.asdict` offers a callback that decides whether an attribute shou

>>> @define
... class UserList:
... users: List[User]
... users: list[User]

>>> asdict(UserList([User("jane@doe.invalid", "s33kred"),
... User("joe@doe.invalid", "p4ssw0rd")]),
Expand Down Expand Up @@ -503,12 +502,12 @@ If you don't mind annotating *all* attributes, you can even drop the `field` and
>>> @define
... class AutoC:
... cls_var: typing.ClassVar[int] = 5 # this one is ignored
... l: typing.List[int] = Factory(list)
... l: list[int] = Factory(list)
... x: int = 1
... foo: str = "every attrib needs a type if auto_attribs=True"
... bar: typing.Any = None
>>> fields(AutoC).l.type
typing.List[int]
list[int]
>>> fields(AutoC).x.type
<class 'int'>
>>> fields(AutoC).foo.type
Expand All @@ -522,35 +521,39 @@ If you don't mind annotating *all* attributes, you can even drop the `field` and

The generated ``__init__`` method will have an attribute called ``__annotations__`` that contains this type information.

If your annotations contain strings (e.g. forward references),
If your annotations contain forward references,
you can resolve these after all references have been defined by using :func:`attr.resolve_types`.
This will replace the *type* attribute in the respective fields.

.. doctest::

>>> import typing
>>> from attr import fields, resolve_types

>>> @define
... class A:
... a: typing.List['A']
... a: 'list[A]'
... b: 'B'
...
>>> @define
... class B:
... a: A
...
>>> fields(A).a.type
typing.List[ForwardRef('A')]
'list[A]'
>>> fields(A).b.type
'B'
>>> resolve_types(A, globals(), locals())
<class 'A'>
>>> fields(A).a.type
typing.List[A]
list[A]
>>> fields(A).b.type
<class 'B'>

.. note::

If you find yourself using string type annotations to handle forward references, wrap the entire type annotation in quotes instead of only the type you need a forward reference to (so ``'list[A]'`` instead of ``list['A']``).
This is a limitation of the Python typing system.

.. warning::

``attrs`` itself doesn't have any features that work on top of type metadata *yet*.
Expand Down
7 changes: 3 additions & 4 deletions docs/types.rst
Expand Up @@ -10,12 +10,11 @@ That means that on modern Python versions, the declaration part of the example f
.. doctest::

>>> import attr
>>> import typing

>>> @attr.s(auto_attribs=True)
... class SomeClass:
... a_number: int = 42
... list_of_numbers: typing.List[int] = attr.Factory(list)
... list_of_numbers: list[int] = attr.Factory(list)

>>> sc = SomeClass(1, [1, 2, 3])
>>> sc
Expand Down Expand Up @@ -71,7 +70,7 @@ To mypy, this code is equivalent to the one above:
@attr.s
class SomeClass(object):
a_number = attr.ib(default=42) # type: int
list_of_numbers = attr.ib(factory=list, type=typing.List[int])
list_of_numbers = attr.ib(factory=list, type=list[int])
pyright
Expand All @@ -86,7 +85,7 @@ Given the following definition, ``pyright`` will generate static type signatures
@attr.define
class SomeClass:
a_number: int = 42
list_of_numbers: typing.List[int] = attr.field(factory=list)
list_of_numbers: list[int] = attr.field(factory=list)

.. warning::

Expand Down

0 comments on commit 956a8d3

Please sign in to comment.