Prepare for narrative docs (#275)
This commit is contained in:
parent
3040bdabbc
commit
3d3d49b4dd
|
@ -144,7 +144,8 @@ or:
|
|||
Local Development Environment
|
||||
-----------------------------
|
||||
|
||||
You can (and should) run our test suite using tox_ however you’ll probably want a more traditional environment too.
|
||||
You can (and should) run our test suite using tox_.
|
||||
However you’ll probably want a more traditional environment too.
|
||||
We highly recommend to develop using the latest Python 3 release because ``attrs`` tries to take advantage of modern features whenever possible.
|
||||
|
||||
First create a `virtual environment <https://virtualenv.pypa.io/>`_.
|
||||
|
|
|
@ -32,6 +32,7 @@ For that, it gives you a class decorator and a way to declaratively define the a
|
|||
.. code-block:: pycon
|
||||
|
||||
>>> import attr
|
||||
|
||||
>>> @attr.s
|
||||
... class SomeClass(object):
|
||||
... a_number = attr.ib(default=42)
|
||||
|
@ -39,19 +40,25 @@ For that, it gives you a class decorator and a way to declaratively define the a
|
|||
...
|
||||
... def hard_math(self, another_number):
|
||||
... return self.a_number + sum(self.list_of_numbers) * another_number
|
||||
|
||||
|
||||
>>> sc = SomeClass(1, [1, 2, 3])
|
||||
>>> sc
|
||||
SomeClass(a_number=1, list_of_numbers=[1, 2, 3])
|
||||
|
||||
>>> sc.hard_math(3)
|
||||
19
|
||||
>>> sc == SomeClass(1, [1, 2, 3])
|
||||
True
|
||||
>>> sc != SomeClass(2, [3, 2, 1])
|
||||
True
|
||||
|
||||
>>> attr.asdict(sc)
|
||||
{'a_number': 1, 'list_of_numbers': [1, 2, 3]}
|
||||
|
||||
>>> SomeClass()
|
||||
SomeClass(a_number=42, list_of_numbers=[])
|
||||
|
||||
>>> C = attr.make_class("C", ["a", "b"])
|
||||
>>> C("foo", "bar")
|
||||
C(a='foo', b='bar')
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
.. _api:
|
||||
|
||||
API
|
||||
===
|
||||
API Reference
|
||||
=============
|
||||
|
||||
.. currentmodule:: attr
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
.. _examples:
|
||||
|
||||
Examples
|
||||
========
|
||||
``attrs`` by Example
|
||||
====================
|
||||
|
||||
|
||||
Basics
|
||||
|
|
|
@ -37,6 +37,40 @@ So it is fairly simple to build your own decorators on top of ``attrs``:
|
|||
|
||||
f = a(b(original_f))
|
||||
|
||||
|
||||
Wrapping the Decorator
|
||||
----------------------
|
||||
|
||||
A more elegant way can be to wrap ``attrs`` altogether and build a class `DSL <https://en.wikipedia.org/wiki/Domain-specific_language>`_ on top of it.
|
||||
|
||||
An example for that is the package `environ_config <https://github.com/hynek/environ_config>`_ that uses ``attrs`` under the hood to define environment-based configurations declaratively without exposing ``attrs`` APIs at all.
|
||||
|
||||
|
||||
Types
|
||||
-----
|
||||
|
||||
``attrs`` offers two ways of attaching type information to attributes:
|
||||
|
||||
- `PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_ annotations on Python 3.6 and later,
|
||||
- and the *type* argument to :func:`attr.ib`.
|
||||
|
||||
This information is available to you:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> import attr
|
||||
>>> @attr.s
|
||||
... class C(object):
|
||||
... x: int = attr.ib()
|
||||
... y = attr.ib(type=str)
|
||||
>>> attr.fields(C).x.type
|
||||
<class 'int'>
|
||||
>>> attr.fields(C).y.type
|
||||
<class 'str'>
|
||||
|
||||
Currently, ``attrs`` doesn't do anything with this information but it's very useful if you'd like to write your own validators or serializers!
|
||||
|
||||
|
||||
.. _extending_metadata:
|
||||
|
||||
Metadata
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
==================================
|
||||
attrs: Classes Without Boilerplate
|
||||
==================================
|
||||
======================================
|
||||
``attrs``: Classes Without Boilerplate
|
||||
======================================
|
||||
|
||||
Release v\ |release| (:doc:`What's new? <changelog>`).
|
||||
|
||||
|
@ -8,29 +8,42 @@ Release v\ |release| (:doc:`What's new? <changelog>`).
|
|||
:start-after: teaser-begin
|
||||
:end-before: -spiel-end-
|
||||
|
||||
If you want to know how this looks like, jump right into :doc:`overview`.
|
||||
If you really want to see ``attrs`` in action, :doc:`examples` will give you a comprehensive rundown of its features.
|
||||
If you're skeptical and want to know how it works first, check out ":doc:`how-does-it-work`".
|
||||
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
``attrs`` is a Python-only package `hosted on PyPI <https://pypi.org/project/attrs/>`_.
|
||||
The recommended installation method is `pip <https://pip.pypa.io/en/stable/>`_-installing into a `virtualenv <https://hynek.me/articles/virtualenv-lives/>`_:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install attrs
|
||||
|
||||
The next three steps should bring you up and running in no time:
|
||||
|
||||
- :doc:`overview` will show you a simple example of ``attrs`` in action and introduce you to its philosophy.
|
||||
Afterwards, you can start writing your own classes, understand what drives ``attrs``'s design, and know what ``@attr.s`` and ``attr.ib()`` stand for.
|
||||
- :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 ``nametuple``\ s!
|
||||
|
||||
|
||||
If you need any help while getting started, feel free to use the ``python-attrs`` tag on `StackOverflow <https://stackoverflow.com/questions/tagged/python-attrs>`_ and someone will surely help you out!
|
||||
|
||||
|
||||
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.
|
||||
- ``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.
|
||||
|
||||
|
||||
.. include:: ../README.rst
|
||||
:start-after: -testimonials-
|
||||
:end-before: -end-
|
||||
|
||||
|
||||
User's Guide
|
||||
============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
overview
|
||||
why
|
||||
examples
|
||||
api
|
||||
extending
|
||||
how-does-it-work
|
||||
|
||||
|
||||
.. include:: ../README.rst
|
||||
:start-after: -project-information-
|
||||
|
||||
|
@ -43,6 +56,22 @@ User's Guide
|
|||
changelog
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
||||
Full Table of Contents
|
||||
======================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
overview
|
||||
why
|
||||
examples
|
||||
api
|
||||
extending
|
||||
how-does-it-work
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
|
|
@ -14,27 +14,27 @@ In order to fulfill its ambitious goal of bringing back the joy to writing class
|
|||
Philosophy
|
||||
==========
|
||||
|
||||
It's about regular classes.
|
||||
``attrs`` for creating well-behaved classes with a type, attributes, methods, and everything that comes with a class.
|
||||
**It's about regular classes.**
|
||||
``attrs`` is for creating well-behaved classes with a type, attributes, methods, and everything that comes with a class.
|
||||
It can be used for data-only containers like ``namedtuple``\ s or ``types.SimpleNamespace`` but they're just a sub-genre of what ``attrs`` is good for.
|
||||
|
||||
The class belongs to the users.
|
||||
**The class belongs to the users.**
|
||||
You define a class and ``attrs`` adds static methods to that class based on the attributes you declare.
|
||||
The end.
|
||||
It doesn't add meta classes.
|
||||
It doesn't add metaclasses.
|
||||
It doesn't add classes you've never heard of to your inheritance tree.
|
||||
An ``attrs`` class in runtime is indistiguishable from a regular class: because it *is* a regular class with a few boilerplate-y methods attached.
|
||||
|
||||
Be light on API impact.
|
||||
**Be light on API impact.**
|
||||
As convenient as it seems at first, ``attrs`` will *not* tack on any methods to your classes save the dunder ones.
|
||||
Hence all the useful :ref:`tools <helpers>` that come with ``attrs`` live in functions that operate on top of instances.
|
||||
Since they take an ``attrs`` instance as their first argument, you can attach them to your classes with one line of code.
|
||||
|
||||
Performance matters.
|
||||
**Performance matters.**
|
||||
``attrs`` runtime impact is very close to zero because all the work is done when the class is defined.
|
||||
Once you're instantiating it, ``attrs`` is out of the picture completely.
|
||||
|
||||
No surprises.
|
||||
**No surprises.**
|
||||
``attrs`` creates classes that arguably work the way a Python beginner would reasonably expect them to work.
|
||||
It doesn't try to guess what you mean because explicit is better than implicit.
|
||||
It doesn't try to be clever because software shouldn't be clever.
|
||||
|
@ -47,7 +47,12 @@ What ``attrs`` Is Not
|
|||
|
||||
``attrs`` does *not* invent some kind of magic system that pulls classes out of its hat using meta classes, runtime introspection, and shaky interdependencies.
|
||||
|
||||
All ``attrs`` does is take your declaration, write dunder methods based on that information, and attach them to your class.
|
||||
All ``attrs`` does is:
|
||||
|
||||
1. take your declaration,
|
||||
2. write dunder methods based on that information,
|
||||
3. and attach them to your class.
|
||||
|
||||
It does *nothing* dynamic at runtime, hence zero runtime overhead.
|
||||
It's still *your* class.
|
||||
Do with it as you please.
|
||||
|
@ -70,10 +75,13 @@ Therefore, the following class definition is identical to the previous one:
|
|||
|
||||
>>> from attr import attrs, attrib, Factory
|
||||
>>> @attrs
|
||||
... class C(object):
|
||||
... x = attrib(default=42)
|
||||
... y = attrib(default=Factory(list))
|
||||
>>> C()
|
||||
C(x=42, y=[])
|
||||
... class SomeClass(object):
|
||||
... a_number = attrib(default=42)
|
||||
... list_of_numbers = attrib(default=Factory(list))
|
||||
...
|
||||
... def hard_math(self, another_number):
|
||||
... return self.a_number + sum(self.list_of_numbers) * another_number
|
||||
>>> SomeClass(1, [1, 2, 3])
|
||||
SomeClass(a_number=1, list_of_numbers=[1, 2, 3])
|
||||
|
||||
Use whichever variant fits your taste better.
|
||||
|
|
11
docs/why.rst
11
docs/why.rst
|
@ -227,9 +227,6 @@ which is quite a mouthful and it doesn't even use any of ``attrs``'s more advanc
|
|||
Also: no tests whatsoever.
|
||||
And who will guarantee you, that you don't accidentally flip the ``<`` in your tenth implementation of ``__gt__``?
|
||||
|
||||
If you don't care and like typing, we're not gonna stop you.
|
||||
But if you ever get sick of the repetitiveness, ``attrs`` will be waiting for you.
|
||||
|
||||
It also should be noted that ``attrs`` is not an all-or-nothing solution.
|
||||
You can freely choose which features you want and disable those that you want more control over:
|
||||
|
||||
|
@ -244,3 +241,11 @@ You can freely choose which features you want and disable those that you want mo
|
|||
... return "<SmartClass(a=%d)>" % (self.a,)
|
||||
>>> SmartClass(1, 2)
|
||||
<SmartClass(a=1)>
|
||||
|
||||
.. admonition:: Summary
|
||||
|
||||
If you don't care and like typing, we're not gonna stop you.
|
||||
|
||||
However it takes a lot of bias and determined rationalization to claim that ``attrs`` raises the mental burden on a project given how difficult it is to find the important bits in a hand-written class and how annoying it is to ensure you've copy-pasted your code correctly over all your classes.
|
||||
|
||||
In any case, if you ever get sick of the repetitiveness and drowning important code in a sea of boilerplate, ``attrs`` will be waiting for you.
|
||||
|
|
Loading…
Reference in New Issue