File: extending.rst

package info (click to toggle)
python-attrs 16.3.0-1~bpo8%2B1
  • links: PTS, VCS
  • area: main
  • in suites: jessie-backports
  • size: 424 kB
  • sloc: python: 2,328; makefile: 158
file content (78 lines) | stat: -rw-r--r-- 2,409 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
.. _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.

So it is fairly simple to build your own decorators on top of ``attrs``:

.. doctest::

   >>> import attr
   >>> def print_attrs(cls):
   ...     print(cls.__attrs_attrs__)
   >>> @print_attrs
   ... @attr.s
   ... class C(object):
   ...     a = attr.ib()
   (Attribute(name='a', default=NOTHING, validator=None, repr=True, cmp=True, hash=True, init=True, convert=None, metadata=mappingproxy({})),)


.. warning::

   The :func:`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
      @b
      def f():
         pass

   is just `syntactic sugar <https://en.wikipedia.org/wiki/Syntactic_sugar>`_ for::

      def original_f():
         pass

      f = a(b(original_f))

.. _extending_metadata:

Metadata
--------

If you're the author of a third-party library with ``attrs`` integration, you may want to take advantage of attribute metadata.

Here are some tips for effective use of metadata:

- Try making your metadata keys and values immutable.
  This keeps the entire ``Attribute`` instances immutable too.

- To avoid metadata key collisions, consider exposing your metadata keys from your modules.::

    from mylib import MY_METADATA_KEY

    @attr.s
    class C(object):
      x = attr.ib(metadata={MY_METADATA_KEY: 1})

  Metadata should be composable, so consider supporting this approach even if you decide implementing your metadata in one of the following ways.

- Expose ``attr.ib`` wrappers for your specific metadata.
  This is a more graceful approach if your users don't require metadata from other libraries.

  .. doctest::

    >>> MY_TYPE_METADATA = '__my_type_metadata'
    >>>
    >>> def typed(cls, default=attr.NOTHING, validator=None, repr=True, cmp=True, hash=True, init=True, convert=None, metadata={}):
    ...     metadata = dict() if not metadata else metadata
    ...     metadata[MY_TYPE_METADATA] = cls
    ...     return attr.ib(default, validator, repr, cmp, hash, init, convert, metadata)
    >>>
    >>> @attr.s
    ... class C(object):
    ...     x = typed(int, default=1, init=False)
    >>> attr.fields(C).x.metadata[MY_TYPE_METADATA]
    <class 'int'>