Skip to content

Commit a6955bf

Browse files
authored
Add narrative docs for type annotations (#406)
* Add narrative docs for type annotations * Better wording * Use better code-block types * Add newsfragment for #238 that refers to these docs
1 parent 4c41099 commit a6955bf

File tree

5 files changed

+73
-4
lines changed

5 files changed

+73
-4
lines changed

README.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ For that, it gives you a class decorator and a way to declaratively define the a
4040
>>> @attr.s
4141
... class SomeClass(object):
4242
... a_number = attr.ib(default=42)
43-
... list_of_numbers = attr.ib(default=attr.Factory(list))
43+
... list_of_numbers = attr.ib(factory=list)
4444
...
4545
... def hard_math(self, another_number):
4646
... return self.a_number + sum(self.list_of_numbers) * another_number
@@ -78,6 +78,8 @@ After *declaring* your attributes ``attrs`` gives you:
7878

7979
*without* writing dull boilerplate code again and again and *without* runtime performance penalties.
8080

81+
On Python 3.6 and later, you can often even drop the calls to ``attr.ib()`` by using `type annotations <http://www.attrs.org/en/latest/types.html>`_.
82+
8183
This gives you the power to use actual classes with actual types in your code instead of confusing ``tuple``\ s or `confusingly behaving <http://www.attrs.org/en/stable/why.html#namedtuples>`_ ``namedtuple``\ s.
8284
Which in turn encourages you to write *small classes* that do `one thing well <https://www.destroyallsoftware.com/talks/boundaries>`_.
8385
Never again violate the `single responsibility principle <https://en.wikipedia.org/wiki/Single_responsibility_principle>`_ just because implementing ``__init__`` et al is a painful drag.

changelog.d/238.change.rst

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
``attrs`` now ships its own `PEP 484 <https://www.python.org/dev/peps/pep-0484/>`_ type hints.
2+
Together with `mypy <http://mypy-lang.org>`_'s ``attrs`` plugin, you've got all you need for writing statically typed code in both Python 2 and 3!
3+
4+
At that occasion, we've also added `narrative docs <http://www.attrs.org/en/stable/types.html>`_ about type annotations in ``attrs``.

docs/index.rst

+5-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ The next three steps should bring you up and running in no time:
2626
- :doc:`examples` will give you a comprehensive tour of ``attrs``'s features.
2727
After reading, you will know about our advanced features and how to use them.
2828
- Finally :doc:`why` gives you a rundown of potential alternatives and why we think ``attrs`` is superior.
29-
Yes, we've heard about ``namedtuple``\ s!
29+
Yes, we've heard about ``namedtuple``\ s and Data Classes!
3030
- If at any point you get confused by some terminology, please check out our :doc:`glossary`.
3131

3232

@@ -36,12 +36,14 @@ If you need any help while getting started, feel free to use the ``python-attrs`
3636
Day-to-Day Usage
3737
================
3838

39-
- Once you're comfortable with the concepts, our :doc:`api` contains all information you need to use ``attrs`` to its fullest.
39+
- :doc:`types` help you to write *correct* and *self-documenting* code.
40+
``attrs`` has first class support for them and even allows you to drop the calls to :func:`attr.ib` on modern Python versions!
4041
- Instance initialization is one of ``attrs`` key feature areas.
4142
Our goal is to relieve you from writing as much code as possible.
4243
:doc:`init` gives you an overview what ``attrs`` has to offer and explains some related philosophies we believe in.
4344
- If you want to put objects into sets or use them as keys in dictionaries, they have to be hashable.
4445
The simplest way to do that is to use frozen classes, but the topic is more complex than it seems and :doc:`hashing` will give you a primer on what to look out for.
46+
- Once you're comfortable with the concepts, our :doc:`api` contains all information you need to use ``attrs`` to its fullest.
4547
- ``attrs`` is built for extension from the ground up.
4648
:doc:`extending` will show you the affordances it offers and how to make it a building block of your own projects.
4749

@@ -74,6 +76,7 @@ Full Table of Contents
7476
overview
7577
why
7678
examples
79+
types
7780
init
7881
hashing
7982
api

docs/types.rst

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
Type Annotations
2+
================
3+
4+
``attrs`` comes with first class support for type annotations for both Python 3.6 (:pep:`526`) and legacy syntax.
5+
6+
On Python 3.6 and later, you can even drop the :func:`attr.ib`\ s if you're willing to annotate *all* attributes.
7+
That means that on modern Python versions, the declaration part of the example from the README can be simplified to:
8+
9+
10+
.. doctest::
11+
12+
>>> import attr
13+
>>> import typing
14+
15+
>>> @attr.s(auto_attribs=True)
16+
... class SomeClass:
17+
... a_number: int = 42
18+
... list_of_numbers: typing.List[int] = attr.Factory(list)
19+
20+
>>> sc = SomeClass(1, [1, 2, 3])
21+
>>> sc
22+
SomeClass(a_number=1, list_of_numbers=[1, 2, 3])
23+
>>> attr.fields(SomeClass).a_number.type
24+
<class 'int'>
25+
26+
You can still use :func:`attr.ib` for advanced features, but you don't have to.
27+
28+
Please note that these types are *only metadata* that can be queried from the class and they aren't used for anything out of the box!
29+
30+
31+
mypy
32+
----
33+
34+
While having a nice syntax for type metadata is great, it's even greater that `mypy <http://mypy-lang.org>`_ as of 0.570 ships with a dedicated ``attrs`` plugin which allows you to statically check your code.
35+
36+
Imagine you add another line that tries to instantiate the defined class using ``SomeClass("23")``.
37+
Mypy will catch that error for you:
38+
39+
.. code-block:: console
40+
41+
$ mypy t.py
42+
t.py:12: error: Argument 1 to "SomeClass" has incompatible type "str"; expected "int"
43+
44+
This happens *without* running your code!
45+
46+
And it also works with *both* Python 2-style annotation styles.
47+
To mypy, this code is equivalent to the one above:
48+
49+
.. code-block:: python
50+
51+
@attr.s
52+
class SomeClass(object):
53+
a_number = attr.ib(default=42) # type: int
54+
list_of_numbers = attr.ib(factory=list, type=typing.List[int])
55+
56+
*****
57+
58+
The addition of static types is certainly one of the most exciting features in the Python ecosystem and helps you writing *correct* and *verified self-documenting* code.
59+
60+
If you don't know where to start, Carl Meyer gave a great talk on `Type-checked Python in the Real World <https://www.youtube.com/watch?v=pMgmKJyWKn8>`_ at PyCon US 2018 that will help you to get started in no time.

docs/why.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ With ``attrs`` your users won't notice a difference because it creates regular,
138138
…Data Classes?
139139
--------------
140140

141-
`PEP 557 <https://www.python.org/dev/peps/pep-0557/>`_ added Data Classes to `Python 3.7 <https://docs.python.org/3.7/whatsnew/3.7.html#pep-557-data-classes>`_ that resemble ``attrs`` in many ways.
141+
:pep:`557` added Data Classes to `Python 3.7 <https://docs.python.org/3.7/whatsnew/3.7.html#pep-557-data-classes>`_ that resemble ``attrs`` in many ways.
142142

143143
They are the result of the Python community's `wish <https://mail.python.org/pipermail/python-ideas/2017-May/045618.html>`_ to have an easier way to write classes in the standard library that doesn't carry the problems of ``namedtuple``\ s.
144144
To that end, ``attrs`` and its developers were involved in the PEP process and while we may disagree with some minor decisions that have been made, it's a fine library and if it stops you from abusing ``namedtuple``\ s, they are a huge win.

0 commit comments

Comments
 (0)