diff --git a/README.rst b/README.rst index 4e616bdcc..f3a05d23e 100644 --- a/README.rst +++ b/README.rst @@ -40,7 +40,7 @@ For that, it gives you a class decorator and a way to declaratively define the a >>> @attr.s ... class SomeClass(object): ... a_number = attr.ib(default=42) - ... list_of_numbers = attr.ib(default=attr.Factory(list)) + ... list_of_numbers = attr.ib(factory=list) ... ... def hard_math(self, another_number): ... return self.a_number + sum(self.list_of_numbers) * another_number @@ -78,6 +78,8 @@ After *declaring* your attributes ``attrs`` gives you: *without* writing dull boilerplate code again and again and *without* runtime performance penalties. +On Python 3.6 and later, you can often even drop the calls to ``attr.ib()`` by using `type annotations `_. + This gives you the power to use actual classes with actual types in your code instead of confusing ``tuple``\ s or `confusingly behaving `_ ``namedtuple``\ s. Which in turn encourages you to write *small classes* that do `one thing well `_. Never again violate the `single responsibility principle `_ just because implementing ``__init__`` et al is a painful drag. diff --git a/changelog.d/238.change.rst b/changelog.d/238.change.rst new file mode 100644 index 000000000..42b9943f7 --- /dev/null +++ b/changelog.d/238.change.rst @@ -0,0 +1,4 @@ +``attrs`` now ships its own `PEP 484 `_ type hints. +Together with `mypy `_'s ``attrs`` plugin, you've got all you need for writing statically typed code in both Python 2 and 3! + +At that occasion, we've also added `narrative docs `_ about type annotations in ``attrs``. diff --git a/docs/index.rst b/docs/index.rst index 8544f19b6..18ce36302 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -26,7 +26,7 @@ The next three steps should bring you up and running in no time: - :doc:`examples` will give you a comprehensive tour of ``attrs``'s features. After reading, you will know about our advanced features and how to use them. - Finally :doc:`why` gives you a rundown of potential alternatives and why we think ``attrs`` is superior. - Yes, we've heard about ``namedtuple``\ s! + Yes, we've heard about ``namedtuple``\ s and Data Classes! - If at any point you get confused by some terminology, please check out our :doc:`glossary`. @@ -36,12 +36,14 @@ If you need any help while getting started, feel free to use the ``python-attrs` Day-to-Day Usage ================ -- Once you're comfortable with the concepts, our :doc:`api` contains all information you need to use ``attrs`` to its fullest. +- :doc:`types` help you to write *correct* and *self-documenting* code. + ``attrs`` has first class support for them and even allows you to drop the calls to :func:`attr.ib` on modern Python versions! - Instance initialization is one of ``attrs`` key feature areas. Our goal is to relieve you from writing as much code as possible. :doc:`init` gives you an overview what ``attrs`` has to offer and explains some related philosophies we believe in. - If you want to put objects into sets or use them as keys in dictionaries, they have to be hashable. 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. +- Once you're comfortable with the concepts, our :doc:`api` contains all information you need to use ``attrs`` to its fullest. - ``attrs`` is built for extension from the ground up. :doc:`extending` will show you the affordances it offers and how to make it a building block of your own projects. @@ -74,6 +76,7 @@ Full Table of Contents overview why examples + types init hashing api diff --git a/docs/types.rst b/docs/types.rst new file mode 100644 index 000000000..60db3f352 --- /dev/null +++ b/docs/types.rst @@ -0,0 +1,60 @@ +Type Annotations +================ + +``attrs`` comes with first class support for type annotations for both Python 3.6 (:pep:`526`) and legacy syntax. + +On Python 3.6 and later, you can even drop the :func:`attr.ib`\ s if you're willing to annotate *all* attributes. +That means that on modern Python versions, the declaration part of the example from the README can be simplified to: + + +.. 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) + + >>> sc = SomeClass(1, [1, 2, 3]) + >>> sc + SomeClass(a_number=1, list_of_numbers=[1, 2, 3]) + >>> attr.fields(SomeClass).a_number.type + + +You can still use :func:`attr.ib` for advanced features, but you don't have to. + +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! + + +mypy +---- + +While having a nice syntax for type metadata is great, it's even greater that `mypy `_ as of 0.570 ships with a dedicated ``attrs`` plugin which allows you to statically check your code. + +Imagine you add another line that tries to instantiate the defined class using ``SomeClass("23")``. +Mypy will catch that error for you: + +.. code-block:: console + + $ mypy t.py + t.py:12: error: Argument 1 to "SomeClass" has incompatible type "str"; expected "int" + +This happens *without* running your code! + +And it also works with *both* Python 2-style annotation styles. +To mypy, this code is equivalent to the one above: + +.. code-block:: python + + @attr.s + class SomeClass(object): + a_number = attr.ib(default=42) # type: int + list_of_numbers = attr.ib(factory=list, type=typing.List[int]) + +***** + +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. + +If you don't know where to start, Carl Meyer gave a great talk on `Type-checked Python in the Real World `_ at PyCon US 2018 that will help you to get started in no time. diff --git a/docs/why.rst b/docs/why.rst index f1bcee3c9..4019aaf05 100644 --- a/docs/why.rst +++ b/docs/why.rst @@ -138,7 +138,7 @@ With ``attrs`` your users won't notice a difference because it creates regular, …Data Classes? -------------- -`PEP 557 `_ added Data Classes to `Python 3.7 `_ that resemble ``attrs`` in many ways. +:pep:`557` added Data Classes to `Python 3.7 `_ that resemble ``attrs`` in many ways. They are the result of the Python community's `wish `_ to have an easier way to write classes in the standard library that doesn't carry the problems of ``namedtuple``\ s. 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.