diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0ffba839e..f60e83eb7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -370,7 +370,7 @@ Changes: `#128 `_ - ``__attrs_post_init__()`` is now run if validation is disabled. `#130 `_ -- Added ``attr.validators.in_(options)`` that, given the allowed `options`, checks whether the attribute value is in it. +- Added ``attr.validators.in_(options)`` that, given the allowed ``options``, checks whether the attribute value is in it. This can be used to check constants, enums, mappings, etc. `#181 `_ - Added ``attr.validators.and_()`` that composes multiple validators into one. diff --git a/docs/api.rst b/docs/api.rst index fe3e4a4dd..76deae368 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,17 +1,15 @@ -.. _api: - API Reference ============= .. currentmodule:: attr -``attrs`` works by decorating a class using :func:`attr.s` and then optionally defining attributes on the class using :func:`attr.ib`. +``attrs`` works by decorating a class using `attr.s` and then optionally defining attributes on the class using `attr.ib`. .. note:: - When this documentation speaks about "``attrs`` attributes" it means those attributes that are defined using :func:`attr.ib` in the class body. + When this documentation speaks about "``attrs`` attributes" it means those attributes that are defined using `attr.ib` in the class body. -What follows is the API explanation, if you'd like a more hands-on introduction, have a look at :doc:`examples`. +What follows is the API explanation, if you'd like a more hands-on introduction, have a look at `examples`. @@ -64,7 +62,7 @@ Core ``attrs`` also comes with a serious business alias ``attr.attrib``. - The object returned by :func:`attr.ib` also allows for setting the default and the validator using decorators: + The object returned by `attr.ib` also allows for setting the default and the validator using decorators: .. doctest:: @@ -90,7 +88,7 @@ Core Instances of this class are frequently used for introspection purposes like: - - :func:`fields` returns a tuple of them. + - `fields` returns a tuple of them. - Validators get them passed as the first argument. .. warning:: @@ -148,6 +146,7 @@ Core .. autoexception:: attr.exceptions.NotAnAttrsClassError .. autoexception:: attr.exceptions.DefaultAlreadySetError .. autoexception:: attr.exceptions.UnannotatedAttributeError +.. autoexception:: attr.exceptions.NotCallableError For example:: @@ -247,7 +246,7 @@ Helpers .. autofunction:: attr.filters.exclude -See :ref:`asdict` for examples. +See :func:`asdict` for examples. .. autofunction:: attr.evolve @@ -357,7 +356,7 @@ Validators .. autofunction:: attr.validators.and_ - For convenience, it's also possible to pass a list to :func:`attr.ib`'s validator argument. + For convenience, it's also possible to pass a list to `attr.ib`'s validator argument. Thus the following two statements are equivalent:: diff --git a/docs/backward-compatibility.rst b/docs/backward-compatibility.rst index 52559f8d4..63466db18 100644 --- a/docs/backward-compatibility.rst +++ b/docs/backward-compatibility.rst @@ -6,14 +6,14 @@ Backward Compatibility ``attrs`` has a very strong backward compatibility policy that is inspired by the policy of the `Twisted framework `_. Put simply, you shouldn't ever be afraid to upgrade ``attrs`` if you're only using its public APIs. -If there will ever be a need to break compatibility, it will be announced in the :doc:`changelog` and raise a ``DeprecationWarning`` for a year (if possible) before it's finally really broken. +If there will ever be a need to break compatibility, it will be announced in the `changelog` and raise a ``DeprecationWarning`` for a year (if possible) before it's finally really broken. .. _exemption: .. warning:: - The structure of the :class:`attr.Attribute` class is exempt from this rule. + The structure of the `attr.Attribute` class is exempt from this rule. It *will* change in the future, but since it should be considered read-only, that shouldn't matter. However if you intend to build extensions on top of ``attrs`` you have to anticipate that. diff --git a/docs/conf.py b/docs/conf.py index 97b2329eb..7fa7f1a86 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -31,6 +31,15 @@ def find_version(*file_paths): # -- General configuration ------------------------------------------------ +# In nitpick mode (-n), still ignore any of the following "broken" references +# to non-types. +nitpick_ignore = [ + ("py:class", "Any value"), + ("py:class", "callable"), + ("py:class", "callables"), + ("py:class", "tuple of types"), +] + # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. @@ -68,6 +77,10 @@ def find_version(*file_paths): # directories to ignore when looking for source files. exclude_patterns = ["_build"] +# The reST default role (used for this markup: `text`) to use for all +# documents. +default_role = "any" + # If true, '()' will be appended to :func: etc. cross-reference text. add_function_parentheses = True @@ -154,7 +167,10 @@ def find_version(*file_paths): ) ] -intersphinx_mapping = {"https://docs.python.org/3": None} +intersphinx_mapping = { + "https://docs.python.org/3": None, + "https://zopeinterface.readthedocs.io/en/latest/": None, +} # Allow non-local URIs so we can have images in CHANGELOG etc. suppress_warnings = ["image.nonlocal_uri"] diff --git a/docs/examples.rst b/docs/examples.rst index 5ee63a1bd..c47099cba 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -1,5 +1,3 @@ -.. _examples: - ``attrs`` by Example ==================== @@ -217,7 +215,7 @@ If you don't set ``kw_only=True``, then there's is no valid attribute ordering a Converting to Collections Types ------------------------------- -When you have a class with data, it often is very convenient to transform that class into a :class:`dict` (for example if you want to serialize it to JSON): +When you have a class with data, it often is very convenient to transform that class into a `dict` (for example if you want to serialize it to JSON): .. doctest:: @@ -225,7 +223,7 @@ When you have a class with data, it often is very convenient to transform that c {'x': 1, 'y': 2} Some fields cannot or should not be transformed. -For that, :func:`attr.asdict` offers a callback that decides whether an attribute should be included: +For that, `attr.asdict` offers a callback that decides whether an attribute should be included: .. doctest:: @@ -241,7 +239,7 @@ For that, :func:`attr.asdict` offers a callback that decides whether an attribut ... filter=lambda attr, value: attr.name != "password") {'users': [{'email': 'jane@doe.invalid'}, {'email': 'joe@doe.invalid'}]} -For the common case where you want to :func:`include ` or :func:`exclude ` certain types or attributes, ``attrs`` ships with a few helpers: +For the common case where you want to `include ` or `exclude ` certain types or attributes, ``attrs`` ships with a few helpers: .. doctest:: @@ -426,7 +424,7 @@ You can use a decorator: ValueError: value out of bounds -``attrs`` ships with a bunch of validators, make sure to :ref:`check them out ` before writing your own: +``attrs`` ships with a bunch of validators, make sure to `check them out ` before writing your own: .. doctest:: @@ -440,7 +438,7 @@ You can use a decorator: ... TypeError: ("'x' must be (got '42' that is a ).", Attribute(name='x', default=NOTHING, factory=NOTHING, validator=>, type=None, kw_only=False), , '42') -Check out :ref:`validators` for more details. +Check out `validators` for more details. Conversion @@ -458,7 +456,7 @@ This can be useful for doing type-conversions on values that you don't want to f >>> o.x 1 -Check out :ref:`converters` for more details. +Check out `converters` for more details. .. _metadata: @@ -481,13 +479,13 @@ All ``attrs`` attributes may include arbitrary metadata in the form of a read-on Metadata is not used by ``attrs``, and is meant to enable rich functionality in third-party libraries. The metadata dictionary follows the normal dictionary rules: keys need to be hashable, and both keys and values are recommended to be immutable. -If you're the author of a third-party library with ``attrs`` integration, please see :ref:`Extending Metadata `. +If you're the author of a third-party library with ``attrs`` integration, please see `Extending Metadata `. Types ----- -``attrs`` also allows you to associate a type with an attribute using either the *type* argument to :func:`attr.ib` or -- as of Python 3.6 -- using `PEP 526 `_-annotations: +``attrs`` also allows you to associate a type with an attribute using either the *type* argument to `attr.ib` or -- as of Python 3.6 -- using `PEP 526 `_-annotations: .. doctest:: @@ -501,7 +499,7 @@ Types >>> attr.fields(C).y.type -If you don't mind annotating *all* attributes, you can even drop the :func:`attr.ib` and assign default values instead: +If you don't mind annotating *all* attributes, you can even drop the `attr.ib` and assign default values instead: .. doctest:: @@ -572,11 +570,11 @@ If you'd like to enforce it, ``attrs`` will try to help: >>> i.x 1 -Please note that true immutability is impossible in Python but it will :ref:`get ` you 99% there. +Please note that true immutability is impossible in Python but it will `get ` you 99% there. By themselves, immutable classes are useful for long-lived objects that should never change; like configurations for example. In order to use them in regular program flow, you'll need a way to easily create new instances with changed attributes. -In Clojure that function is called `assoc `_ and ``attrs`` shamelessly imitates it: :func:`attr.evolve`: +In Clojure that function is called `assoc `_ and ``attrs`` shamelessly imitates it: `attr.evolve`: .. doctest:: @@ -598,7 +596,7 @@ Other Goodies ------------- Sometimes you may want to create a class programmatically. -``attrs`` won't let you down and gives you :func:`attr.make_class` : +``attrs`` won't let you down and gives you `attr.make_class` : .. doctest:: @@ -625,7 +623,7 @@ You can still have power over the attributes if you pass a dictionary of name: ` >>> i.y [] -If you need to dynamically make a class with :func:`attr.make_class` and it needs to be a subclass of something else than ``object``, use the ``bases`` argument: +If you need to dynamically make a class with `attr.make_class` and it needs to be a subclass of something else than ``object``, use the ``bases`` argument: .. doctest:: diff --git a/docs/extending.rst b/docs/extending.rst index fe6883cf2..dcaebee62 100644 --- a/docs/extending.rst +++ b/docs/extending.rst @@ -1,10 +1,8 @@ -.. _extending: - Extending ========= Each ``attrs``-decorated class has a ``__attrs_attrs__`` class attribute. -It is a tuple of :class:`attr.Attribute` carrying meta-data about each attribute. +It is a tuple of `attr.Attribute` carrying meta-data about each attribute. So it is fairly simple to build your own decorators on top of ``attrs``: @@ -23,7 +21,7 @@ So it is fairly simple to build your own decorators on top of ``attrs``: .. warning:: - The :func:`attr.s` decorator **must** be applied first because it puts ``__attrs_attrs__`` in place! + The `attr.s` decorator **must** be applied first because it puts ``__attrs_attrs__`` in place! That means that is has to come *after* your decorator because:: @a @@ -53,7 +51,7 @@ Types ``attrs`` offers two ways of attaching type information to attributes: - `PEP 526 `_ annotations on Python 3.6 and later, -- and the *type* argument to :func:`attr.ib`. +- and the *type* argument to `attr.ib`. This information is available to you: diff --git a/docs/glossary.rst b/docs/glossary.rst index 8beb398a0..6edf9d102 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -36,14 +36,14 @@ Glossary - Slotted classes can inherit from other classes just like non-slotted classes, but some of the benefits of slotted classes are lost if you do that. If you must inherit from other classes, try to inherit only from other slotted classes. - - Slotted classes must implement :meth:`__getstate__ ` and :meth:`__setstate__ ` to be serializable with :mod:`pickle` protocol 0 and 1. + - Slotted classes must implement :meth:`__getstate__ ` and :meth:`__setstate__ ` to be serializable with `pickle` protocol 0 and 1. Therefore, ``attrs`` creates these methods automatically for ``slots=True`` classes (Python 2 uses protocol 0 by default). .. note:: If the ``@attr.s(slots=True)`` decorated class already implements the :meth:`__getstate__ ` and :meth:`__setstate__ ` methods, they will be *overridden* by ``attrs`` autogenerated implementation. - Also, `think twice `_ before using :mod:`pickle`. + Also, `think twice `_ before using `pickle`. - Slotted classes are weak-referenceable by default. This can be disabled in CPython by passing ``weakref_slot=False`` to ``@attr.s`` [#pypyweakref]_. diff --git a/docs/hashing.rst b/docs/hashing.rst index 4d31107a0..8bf354023 100644 --- a/docs/hashing.rst +++ b/docs/hashing.rst @@ -15,10 +15,10 @@ Hash Method Generation Setting ``hash`` yourself can have unexpected consequences so we recommend to tinker with it only if you know exactly what you're doing. Under certain circumstances, it's necessary for objects to be *hashable*. -For example if you want to put them into a :class:`set` or if you want to use them as keys in a :class:`dict`. +For example if you want to put them into a `set` or if you want to use them as keys in a `dict`. The *hash* of an object is an integer that represents the contents of an object. -It can be obtained by calling :func:`hash` on an object and is implemented by writing a ``__hash__`` method for your class. +It can be obtained by calling `hash` on an object and is implemented by writing a ``__hash__`` method for your class. ``attrs`` will happily write a ``__hash__`` method for you [#fn1]_, however it will *not* do so by default. Because according to the definition_ from the official Python docs, the returned hash has to fulfill certain constraints: @@ -26,7 +26,7 @@ Because according to the definition_ from the official Python docs, the returned #. Two objects that are equal, **must** have the same hash. This means that if ``x == y``, it *must* follow that ``hash(x) == hash(y)``. - By default, Python classes are compared *and* hashed by their :func:`id`. + By default, Python classes are compared *and* hashed by their `id`. That means that every instance of a class has a different hash, no matter what attributes it carries. It follows that the moment you (or ``attrs``) change the way equality is handled by implementing ``__eq__`` which is based on attribute values, this constraint is broken. @@ -65,7 +65,7 @@ For a more thorough explanation of this topic, please refer to this blog post: ` Hashing and Mutability ---------------------- -Changing any field involved in hash code computation after the first call to `__hash__` (typically this would be after its insertion into a hash-based collection) can result in silent bugs. +Changing any field involved in hash code computation after the first call to ``__hash__`` (typically this would be after its insertion into a hash-based collection) can result in silent bugs. Therefore, it is strongly recommended that hashable classes be ``frozen.`` Beware, however, that this is not a complete guarantee of safety: if a field points to an object and that object is mutated, the hash code may change, but ``frozen`` will not protect you. diff --git a/docs/how-does-it-work.rst b/docs/how-does-it-work.rst index 1de7cecf6..62c715e0b 100644 --- a/docs/how-does-it-work.rst +++ b/docs/how-does-it-work.rst @@ -39,7 +39,7 @@ No magic, no meta programming, no expensive introspection at runtime. Everything until this point happens exactly *once* when the class is defined. As soon as a class is done, it's done. -And it's just a regular Python class like any other, except for a single ``__attrs_attrs__`` attribute that can be used for introspection or for writing your own tools and decorators on top of ``attrs`` (like :func:`attr.asdict`). +And it's just a regular Python class like any other, except for a single ``__attrs_attrs__`` attribute that can be used for introspection or for writing your own tools and decorators on top of ``attrs`` (like `attr.asdict`). And once you start instantiating your classes, ``attrs`` is out of your way completely. @@ -51,7 +51,7 @@ This **static** approach was very much a design goal of ``attrs`` and what I str Immutability ------------ -In order to give you immutability, ``attrs`` will attach a ``__setattr__`` method to your class that raises a :exc:`attr.exceptions.FrozenInstanceError` whenever anyone tries to set an attribute. +In order to give you immutability, ``attrs`` will attach a ``__setattr__`` method to your class that raises a `attr.exceptions.FrozenInstanceError` whenever anyone tries to set an attribute. Depending on whether a class is a dict class or a slotted class, ``attrs`` uses a different technique to circumvent that limitation in the ``__init__`` method. diff --git a/docs/index.rst b/docs/index.rst index 8e88be0d2..08e6c75fe 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,7 +2,7 @@ ``attrs``: Classes Without Boilerplate ====================================== -Release v\ |release| (:doc:`What's new? `). +Release v\ |release| (`What's new? `). .. include:: ../README.rst :start-after: teaser-begin @@ -21,13 +21,13 @@ The recommended installation method is `pip `_-i 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. +- `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. +- `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. +- Finally `why` gives you a rundown of potential alternatives and why we think ``attrs`` is superior. 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`. +- If at any point you get confused by some terminology, please check out our `glossary`. If you need any help while getting started, feel free to use the ``python-attrs`` tag on `StackOverflow `_ and someone will surely help you out! @@ -36,16 +36,16 @@ If you need any help while getting started, feel free to use the ``python-attrs` Day-to-Day Usage ================ -- :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! +- `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 `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. + `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. + The simplest way to do that is to use frozen classes, but the topic is more complex than it seems and `hashing` will give you a primer on what to look out for. +- Once you're comfortable with the concepts, our `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. + `extending` will show you the affordances it offers and how to make it a building block of your own projects. .. include:: ../README.rst @@ -89,5 +89,5 @@ Full Table of Contents Indices and tables ================== -* :ref:`genindex` -* :ref:`search` +* `genindex` +* `search` diff --git a/docs/init.rst b/docs/init.rst index 109fcff9e..9ff92411f 100644 --- a/docs/init.rst +++ b/docs/init.rst @@ -15,7 +15,7 @@ So assuming you use an ORM and want to extract 2D points from a row object, do n pt = Point(row) -Instead, write a :func:`classmethod` that will extract it for you:: +Instead, write a `classmethod` that will extract it for you:: @attr.s class Point(object): @@ -97,7 +97,7 @@ This is when default values come into play: C(a=42, b=[], c=[], d={}) It's important that the decorated method -- or any other method or property! -- doesn't have the same name as the attribute, otherwise it would overwrite the attribute definition. -You also cannot use type annotations to elide the :func:`attr.ib` call for ``d`` as explained in :doc:`types`. +You also cannot use type annotations to elide the `attr.ib` call for ``d`` as explained in `types`. Please note that as with function and method signatures, ``default=[]`` will *not* do what you may think it might do: @@ -162,13 +162,13 @@ If the value does not pass the validator's standards, it just raises an appropri ... ValueError: x must be smaller or equal to 42 -Again, it's important that the decorated method doesn't have the same name as the attribute and that you can't elide the call to :func:`attr.ib`. +Again, it's important that the decorated method doesn't have the same name as the attribute and that you can't elide the call to `attr.ib`. Callables ~~~~~~~~~ -If you want to re-use your validators, you should have a look at the ``validator`` argument to :func:`attr.ib()`. +If you want to re-use your validators, you should have a look at the ``validator`` argument to `attr.ib`. It takes either a callable or a list of callables (usually functions) and treats them as validators that receive the same arguments as with the decorator approach. @@ -191,9 +191,9 @@ Since the validators runs *after* the instance is initialized, you can refer to ... ValueError: 'x' has to be smaller than 'y'! -This example also shows of some syntactic sugar for using the :func:`attr.validators.and_` validator: if you pass a list, all validators have to pass. +This example also shows of some syntactic sugar for using the `attr.validators.and_` validator: if you pass a list, all validators have to pass. -``attrs`` won't intercept your changes to those attributes but you can always call :func:`attr.validate` on any instance to verify that it's still valid: +``attrs`` won't intercept your changes to those attributes but you can always call `attr.validate` on any instance to verify that it's still valid: .. doctest:: @@ -204,7 +204,7 @@ This example also shows of some syntactic sugar for using the :func:`attr.valida ... ValueError: 'x' has to be smaller than 'y'! -``attrs`` ships with a bunch of validators, make sure to :ref:`check them out ` before writing your own: +``attrs`` ships with a bunch of validators, make sure to `check them out ` before writing your own: .. doctest:: @@ -336,7 +336,7 @@ Please note that you can't directly set attributes on frozen classes: ... attr.exceptions.FrozenInstanceError: can't set attribute -If you need to set attributes on a frozen class, you'll have to resort to the :ref:`same trick ` as ``attrs`` and use :meth:`object.__setattr__`: +If you need to set attributes on a frozen class, you'll have to resort to the `same trick ` as ``attrs`` and use :meth:`object.__setattr__`: .. doctest:: diff --git a/docs/overview.rst b/docs/overview.rst index 47b022ff3..7880d44c7 100644 --- a/docs/overview.rst +++ b/docs/overview.rst @@ -27,7 +27,7 @@ Philosophy **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 ` that come with ``attrs`` live in functions that operate on top of instances. + Hence all the useful `tools ` 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.** @@ -39,7 +39,7 @@ Philosophy 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. -Check out :doc:`how-does-it-work` if you'd like to know how it achieves all of the above. +Check out `how-does-it-work` if you'd like to know how it achieves all of the above. What ``attrs`` Is Not diff --git a/docs/types.rst b/docs/types.rst index 798d864e4..890f68ef5 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -3,7 +3,7 @@ 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. +On Python 3.6 and later, you can even drop the `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: @@ -23,11 +23,11 @@ That means that on modern Python versions, the declaration part of the example f >>> attr.fields(SomeClass).a_number.type -You will still need :func:`attr.ib` for advanced features, but not for the common cases. +You will still need `attr.ib` for advanced features, but not for the common cases. One of those features are the decorator-based features like defaults. It's important to remember that ``attrs`` doesn't do any magic behind your back. -All the decorators are implemented using an object that is returned by the call to :func:`attr.ib`. +All the decorators are implemented using an object that is returned by the call to `attr.ib`. Attributes that only carry a class annotation do not have that object so trying to call a method on it will inevitably fail. diff --git a/docs/why.rst b/docs/why.rst index 980741642..77d68c1f5 100644 --- a/docs/why.rst +++ b/docs/why.rst @@ -1,5 +1,3 @@ -.. _why: - Why not… ======== @@ -57,7 +55,7 @@ Adding an attribute to a class concerns only those who actually care about that …namedtuples? ------------- -:func:`collections.namedtuple`\ s are tuples with names, not classes. [#history]_ +`collections.namedtuple`\ s are tuples with names, not classes. [#history]_ Since writing classes is tiresome in Python, every now and then someone discovers all the typing they could save and gets really excited. However that convenience comes at a price. @@ -127,7 +125,7 @@ With ``attrs`` your users won't notice a difference because it creates regular, .. [#pollution] ``attrs`` only adds a single attribute: ``__attrs_attrs__`` for introspection. All helpers are functions in the ``attr`` package. Since they take the instance as first argument, you can easily attach them to your classes under a name of your own choice. -.. [#iter] :func:`attr.astuple` can be used to get that behavior in ``attrs`` on *explicit demand*. +.. [#iter] `attr.astuple` can be used to get that behavior in ``attrs`` on *explicit demand*. .. [#immutable] ``attrs`` offers *optional* immutability through the ``frozen`` keyword. .. [#perf] Although ``attrs`` would serve you just as well! Since both employ the same method of writing and compiling Python code for you, the performance penalty is negligible at worst and in some cases ``attrs`` is even faster if you use ``slots=True`` (which is generally a good idea anyway). diff --git a/src/attr/_funcs.py b/src/attr/_funcs.py index ff50e3dce..c077e4284 100644 --- a/src/attr/_funcs.py +++ b/src/attr/_funcs.py @@ -24,7 +24,7 @@ def asdict( ``attrs``-decorated. :param callable filter: A callable whose return code determines whether an attribute or element is included (``True``) or dropped (``False``). Is - called with the :class:`attr.Attribute` as the first argument and the + called with the `attr.Attribute` as the first argument and the value as the second argument. :param callable dict_factory: A callable to produce dictionaries from. For example, to produce ordered dictionaries instead of normal Python @@ -130,7 +130,7 @@ def astuple( ``attrs``-decorated. :param callable filter: A callable whose return code determines whether an attribute or element is included (``True``) or dropped (``False``). Is - called with the :class:`attr.Attribute` as the first argument and the + called with the `attr.Attribute` as the first argument and the value as the second argument. :param callable tuple_factory: A callable to produce tuples from. For example, to produce lists instead of tuples. @@ -239,7 +239,7 @@ def assoc(inst, **changes): class. .. deprecated:: 17.1.0 - Use :func:`evolve` instead. + Use `evolve` instead. """ import warnings diff --git a/src/attr/_make.py b/src/attr/_make.py index d7dfaaa44..037d7ecf2 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -88,30 +88,30 @@ def attrib( .. warning:: Does *not* do anything unless the class is also decorated with - :func:`attr.s`! + `attr.s`! :param default: A value that is used if an ``attrs``-generated ``__init__`` is used and no value is passed while instantiating or the attribute is excluded using ``init=False``. - If the value is an instance of :class:`Factory`, its callable will be + If the value is an instance of `Factory`, its callable will be used to construct a new value (useful for mutable data types like lists or dicts). If a default is not set (or set manually to ``attr.NOTHING``), a value - *must* be supplied when instantiating; otherwise a :exc:`TypeError` + *must* be supplied when instantiating; otherwise a `TypeError` will be raised. The default can also be set using decorator notation as shown below. - :type default: Any value. + :type default: Any value :param callable factory: Syntactic sugar for ``default=attr.Factory(callable)``. - :param validator: :func:`callable` that is called by ``attrs``-generated + :param validator: `callable` that is called by ``attrs``-generated ``__init__`` methods after the instance has been initialized. They - receive the initialized instance, the :class:`Attribute`, and the + receive the initialized instance, the `Attribute`, and the passed value. The return value is *not* inspected so the validator has to throw an @@ -121,7 +121,7 @@ def attrib( all pass. Validators can be globally disabled and re-enabled using - :func:`get_run_validators`. + `get_run_validators`. The validator can also be set using decorator notation as shown below. @@ -146,13 +146,13 @@ def attrib( method. It is possible to set this to ``False`` and set a default value. In that case this attributed is unconditionally initialized with the specified default value or factory. - :param callable converter: :func:`callable` that is called by + :param callable converter: `callable` that is called by ``attrs``-generated ``__init__`` methods to converter attribute's value to the desired format. It is given the passed-in value, and the returned value will be used as the new value of the attribute. The value is converted before being passed to the validator, if any. :param metadata: An arbitrary mapping, to be used by third-party - components. See :ref:`extending_metadata`. + components. See `extending_metadata`. :param type: The type of the attribute. In Python 3.6 or greater, the preferred method to specify the type is using a variable annotation (see `PEP 526 `_). @@ -162,7 +162,7 @@ def attrib( Please note that ``attrs`` doesn't do anything with this metadata by itself. You can use it as part of your own code or for - :doc:`static type checking `. + `static type checking `. :param kw_only: Make this attribute keyword-only (Python 3+) in the generated ``__init__`` (if ``init`` is ``False``, this parameter is ignored). @@ -729,9 +729,9 @@ def attrs( r""" A class decorator that adds `dunder `_\ -methods according to the - specified attributes using :func:`attr.ib` or the *these* argument. + specified attributes using `attr.ib` or the *these* argument. - :param these: A dictionary of name to :func:`attr.ib` mappings. This is + :param these: A dictionary of name to `attr.ib` mappings. This is useful to avoid the definition of your attributes within the class body because you can't (e.g. if you want to add ``__repr__`` methods to Django models) or don't want to. @@ -739,12 +739,12 @@ def attrs( If *these* is not ``None``, ``attrs`` will *not* search the class body for attributes and will *not* remove any attributes from it. - If *these* is an ordered dict (:class:`dict` on Python 3.6+, - :class:`collections.OrderedDict` otherwise), the order is deduced from + If *these* is an ordered dict (`dict` on Python 3.6+, + `collections.OrderedDict` otherwise), the order is deduced from the order of the attributes inside *these*. Otherwise the order of the definition of the attributes is used. - :type these: :class:`dict` of :class:`str` to :func:`attr.ib` + :type these: `dict` of `str` to `attr.ib` :param str repr_ns: When using nested classes, there's no way in Python 2 to automatically detect that. Therefore it's possible to set the @@ -753,7 +753,7 @@ def attrs( representation of ``attrs`` attributes.. :param bool str: Create a ``__str__`` method that is identical to ``__repr__``. This is usually not necessary except for - :class:`Exception`\ s. + `Exception`\ s. :param bool cmp: Create ``__eq__``, ``__ne__``, ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` methods that compare the class as if it were a tuple of its ``attrs`` attributes. But the attributes are *only* @@ -783,10 +783,10 @@ def attrs( argument name. If a ``__attrs_post_init__`` method exists on the class, it will be called after the class is fully initialized. :param bool slots: Create a slots_-style class that's more - memory-efficient. See :ref:`slots` for further ramifications. + memory-efficient. See `slots` for further ramifications. :param bool frozen: Make instances immutable after initialization. If someone attempts to modify a frozen instance, - :exc:`attr.exceptions.FrozenInstanceError` is raised. + `attr.exceptions.FrozenInstanceError` is raised. Please note: @@ -795,7 +795,7 @@ def attrs( 2. True immutability is impossible in Python. - 3. This *does* have a minor a runtime performance :ref:`impact + 3. This *does* have a minor a runtime performance `impact ` when initializing new instances. In other words: ``__init__`` is slightly slower with ``frozen=True``. @@ -811,17 +811,17 @@ def attrs( (Python 3.6 and later only) from the class body. In this case, you **must** annotate every field. If ``attrs`` - encounters a field that is set to an :func:`attr.ib` but lacks a type - annotation, an :exc:`attr.exceptions.UnannotatedAttributeError` is + encounters a field that is set to an `attr.ib` but lacks a type + annotation, an `attr.exceptions.UnannotatedAttributeError` is raised. Use ``field_name: typing.Any = attr.ib(...)`` if you don't want to set a type. If you assign a value to those attributes (e.g. ``x: int = 42``), that value becomes the default value like if it were passed using - ``attr.ib(default=42)``. Passing an instance of :class:`Factory` also + ``attr.ib(default=42)``. Passing an instance of `Factory` also works as expected. - Attributes annotated as :data:`typing.ClassVar` are **ignored**. + Attributes annotated as `typing.ClassVar` are **ignored**. .. _`PEP 526`: https://www.python.org/dev/peps/pep-0526/ :param bool kw_only: Make all attributes keyword-only (Python 3+) @@ -834,7 +834,7 @@ def attrs( fields involved in hash code computation or mutations of the objects those fields point to after object creation. If such changes occur, the behavior of the object's hash code is undefined. - :param bool auto_exc: If the class subclasses :class:`BaseException` + :param bool auto_exc: If the class subclasses `BaseException` (which implicitly includes any subclass of any exception), the following happens to behave like a well-behaved Python exceptions class: @@ -861,7 +861,7 @@ def attrs( .. versionadded:: 18.2.0 *weakref_slot* .. deprecated:: 18.2.0 ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a - :class:`DeprecationWarning` if the classes compared are subclasses of + `DeprecationWarning` if the classes compared are subclasses of each other. ``__eq`` and ``__ne__`` never tried to compared subclasses to each other. .. versionchanged:: 19.2.0 @@ -1315,7 +1315,7 @@ def fields(cls): :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` class. - :rtype: tuple (with name accessors) of :class:`attr.Attribute` + :rtype: tuple (with name accessors) of `attr.Attribute` .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields by name. @@ -1342,7 +1342,7 @@ def fields_dict(cls): class. :rtype: an ordered dict where keys are attribute names and values are - :class:`attr.Attribute`\\ s. This will be a :class:`dict` if it's + `attr.Attribute`\\ s. This will be a `dict` if it's naturally ordered like on Python 3.6+ or an :class:`~collections.OrderedDict` otherwise. @@ -1672,10 +1672,10 @@ class Attribute(object): :attribute name: The name of the attribute. - Plus *all* arguments of :func:`attr.ib` (except for `factory` which is only - syntactic sugar for ``default=Factory(...)``. + Plus *all* arguments of `attr.ib` (except for ``factory`` + which is only syntactic sugar for ``default=Factory(...)``. - For the version history of the fields, see :func:`attr.ib`. + For the version history of the fields, see `attr.ib`. """ __slots__ = ( @@ -1939,7 +1939,7 @@ class Factory(object): """ Stores a factory callable. - If passed as the default value to :func:`attr.ib`, the factory is used to + If passed as the default value to `attr.ib`, the factory is used to generate a new value. :param callable factory: A callable that takes either none or exactly one @@ -1972,15 +1972,15 @@ def make_class(name, attrs, bases=(object,), **attributes_arguments): :param attrs: A list of names or a dictionary of mappings of names to attributes. - If *attrs* is a list or an ordered dict (:class:`dict` on Python 3.6+, - :class:`collections.OrderedDict` otherwise), the order is deduced from + If *attrs* is a list or an ordered dict (`dict` on Python 3.6+, + `collections.OrderedDict` otherwise), the order is deduced from the order of the names or attributes inside *attrs*. Otherwise the order of the definition of the attributes is used. - :type attrs: :class:`list` or :class:`dict` + :type attrs: `list` or `dict` :param tuple bases: Classes that the new class will subclass. - :param attributes_arguments: Passed unmodified to :func:`attr.s`. + :param attributes_arguments: Passed unmodified to `attr.s`. :return: A new class with *attrs*. :rtype: type diff --git a/src/attr/converters.py b/src/attr/converters.py index 37c4a07a0..859289784 100644 --- a/src/attr/converters.py +++ b/src/attr/converters.py @@ -32,14 +32,14 @@ def default_if_none(default=NOTHING, factory=None): result of *factory*. :param default: Value to be used if ``None`` is passed. Passing an instance - of :class:`attr.Factory` is supported, however the ``takes_self`` option + of `attr.Factory` is supported, however the ``takes_self`` option is *not*. :param callable factory: A callable that takes not parameters whose result is used if ``None`` is passed. :raises TypeError: If **neither** *default* or *factory* is passed. :raises TypeError: If **both** *default* and *factory* are passed. - :raises ValueError: If an instance of :class:`attr.Factory` is passed with + :raises ValueError: If an instance of `attr.Factory` is passed with ``takes_self=True``. .. versionadded:: 18.2.0 diff --git a/src/attr/exceptions.py b/src/attr/exceptions.py index 1fa4e47e7..d1b76185c 100644 --- a/src/attr/exceptions.py +++ b/src/attr/exceptions.py @@ -6,7 +6,7 @@ class FrozenInstanceError(AttributeError): A frozen/immutable instance has been attempted to be modified. It mirrors the behavior of ``namedtuples`` by using the same error message - and subclassing :exc:`AttributeError`. + and subclassing `AttributeError`. .. versionadded:: 16.1.0 """ diff --git a/src/attr/filters.py b/src/attr/filters.py index f1c69b8ba..dc47e8fa3 100644 --- a/src/attr/filters.py +++ b/src/attr/filters.py @@ -1,5 +1,5 @@ """ -Commonly useful filters for :func:`attr.asdict`. +Commonly useful filters for `attr.asdict`. """ from __future__ import absolute_import, division, print_function @@ -23,9 +23,9 @@ def include(*what): Whitelist *what*. :param what: What to whitelist. - :type what: :class:`list` of :class:`type` or :class:`attr.Attribute`\\ s + :type what: `list` of `type` or `attr.Attribute`\\ s - :rtype: :class:`callable` + :rtype: `callable` """ cls, attrs = _split_what(what) @@ -40,9 +40,9 @@ def exclude(*what): Blacklist *what*. :param what: What to blacklist. - :type what: :class:`list` of classes or :class:`attr.Attribute`\\ s. + :type what: `list` of classes or `attr.Attribute`\\ s. - :rtype: :class:`callable` + :rtype: `callable` """ cls, attrs = _split_what(what) diff --git a/src/attr/validators.py b/src/attr/validators.py index 5c7bb5686..839d310c3 100644 --- a/src/attr/validators.py +++ b/src/attr/validators.py @@ -53,15 +53,15 @@ def __repr__(self): def instance_of(type): """ - A validator that raises a :exc:`TypeError` if the initializer is called + A validator that raises a `TypeError` if the initializer is called with a wrong type for this particular attribute (checks are performed using - :func:`isinstance` therefore it's also valid to pass a tuple of types). + `isinstance` therefore it's also valid to pass a tuple of types). :param type: The type to check for. :type type: type or tuple of types :raises TypeError: With a human readable error message, the attribute - (of type :class:`attr.Attribute`), the expected type, and the value it + (of type `attr.Attribute`), the expected type, and the value it got. """ return _InstanceOfValidator(type) @@ -96,17 +96,17 @@ def __repr__(self): def matches_re(regex, flags=0, func=None): r""" - A validator that raises :exc:`ValueError` if the initializer is called + A validator that raises `ValueError` if the initializer is called with a string that doesn't match *regex*. :param str regex: a regex string to match against :param int flags: flags that will be passed to the underlying re function (default 0) - :param callable func: which underlying :mod:`re` function to call (options - are :func:`re.fullmatch`, :func:`re.search`, :func:`re.match`, default - is ``None`` which means either :func:`re.fullmatch` or an emulation of + :param callable func: which underlying `re` function to call (options + are `re.fullmatch`, `re.search`, `re.match`, default + is ``None`` which means either `re.fullmatch` or an emulation of it on Python 2). For performance reasons, they won't be used directly - but on a pre-:func:`re.compile`\ ed pattern. + but on a pre-`re.compile`\ ed pattern. .. versionadded:: 19.2.0 """ @@ -166,7 +166,7 @@ def __repr__(self): def provides(interface): """ - A validator that raises a :exc:`TypeError` if the initializer is called + A validator that raises a `TypeError` if the initializer is called with an object that does not provide the requested *interface* (checks are performed using ``interface.providedBy(value)`` (see `zope.interface `_). @@ -174,7 +174,7 @@ def provides(interface): :param zope.interface.Interface interface: The interface to check for. :raises TypeError: With a human readable error message, the attribute - (of type :class:`attr.Attribute`), the expected interface, and the + (of type `attr.Attribute`), the expected interface, and the value it got. """ return _ProvidesValidator(interface) @@ -204,7 +204,7 @@ def optional(validator): :param validator: A validator (or a list of validators) that is used for non-``None`` values. - :type validator: callable or :class:`list` of callables. + :type validator: callable or `list` of callables. .. versionadded:: 15.1.0 .. versionchanged:: 17.1.0 *validator* can be a list of validators. @@ -239,15 +239,15 @@ def __repr__(self): def in_(options): """ - A validator that raises a :exc:`ValueError` if the initializer is called + A validator that raises a `ValueError` if the initializer is called with a value that does not belong in the options provided. The check is performed using ``value in options``. :param options: Allowed options. - :type options: list, tuple, :class:`enum.Enum`, ... + :type options: list, tuple, `enum.Enum`, ... :raises ValueError: With a human readable error message, the attribute (of - type :class:`attr.Attribute`), the expected options, and the value it + type `attr.Attribute`), the expected options, and the value it got. .. versionadded:: 17.1.0 @@ -279,14 +279,14 @@ def __repr__(self): def is_callable(): """ - A validator that raises a :class:`attr.exceptions.NotCallableError` - if the initializer is called with a value for this particular attribute + A validator that raises a `attr.exceptions.NotCallableError` if the + initializer is called with a value for this particular attribute that is not callable. .. versionadded:: 19.1.0 :raises `attr.exceptions.NotCallableError`: With a human readable error - message containing the attribute (:class:`attr.Attribute`) name, + message containing the attribute (`attr.Attribute`) name, and the value it got. """ return _IsCallableValidator() diff --git a/tests/test_validators.py b/tests/test_validators.py index d2ab2d7b7..bd2f2a885 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -439,7 +439,7 @@ def test_noncallable_validators( self, member_validator, iterable_validator ): """ - Raise :class:`TypeError` if any validators are not callable. + Raise `TypeError` if any validators are not callable. """ with pytest.raises(TypeError) as e: deep_iterable(member_validator, iterable_validator) @@ -557,7 +557,7 @@ def test_noncallable_validators( self, key_validator, value_validator, mapping_validator ): """ - Raise :class:`TypeError` if any validators are not callable. + Raise `TypeError` if any validators are not callable. """ with pytest.raises(TypeError) as e: deep_mapping(key_validator, value_validator, mapping_validator) @@ -574,7 +574,7 @@ def test_noncallable_validators( def test_fail_invalid_mapping(self): """ - Raise :class:`TypeError` if mapping validator fails. + Raise `TypeError` if mapping validator fails. """ key_validator = instance_of(str) value_validator = instance_of(int) diff --git a/tox.ini b/tox.ini index d76b85182..1a3b5ec2b 100644 --- a/tox.ini +++ b/tox.ini @@ -59,8 +59,8 @@ commands = pre-commit run --all-files basepython = python3.7 extras = docs commands = - sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/_build/html - sphinx-build -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html + sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html + sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html python -m doctest README.rst