2017-10-26 15:55:45 +00:00
API Reference
=============
2015-01-28 13:36:11 +00:00
.. currentmodule :: attr
2021-11-24 08:39:41 +00:00
`` attrs `` works by decorating a class using `attr.define` or `attr.s` and then optionally defining attributes on the class using `attr.field` , `attr.ib` , or a type annotation.
2015-01-28 13:36:11 +00:00
2021-11-24 08:39:41 +00:00
If you're confused by the many names, please check out `names` for clarification.
2015-01-28 15:02:18 +00:00
2019-09-09 13:02:16 +00:00
What follows is the API explanation, if you'd like a more hands-on introduction, have a look at `examples` .
2015-01-28 13:36:11 +00:00
Core
----
2020-08-17 14:22:33 +00:00
2021-04-09 18:36:10 +00:00
.. note ::
`` attrs `` 20.1.0 added a bunch of nicer APIs (sometimes referred to as next generation -- or NG -- APIs) that were intended to become the main way of defining classes in the future.
As of 21.1.0, they are not provisional anymore and are the **recommended** way to use `` attrs `` !
The next step will be adding an importable `` attrs `` namespace.
The documentation will be updated successively.
2020-08-17 14:22:33 +00:00
2021-04-09 18:36:10 +00:00
Please have a look at :ref: `next-gen` !
2020-08-17 14:22:33 +00:00
2020-07-20 10:43:10 +00:00
.. autodata :: attr.NOTHING
2021-05-18 05:02:06 +00:00
.. autofunction :: attr.s(these=None, repr_ns=None, repr=None, cmp=None, hash=None, init=None, slots=False, frozen=False, weakref_slot=True, str=False, auto_attribs=False, kw_only=False, cache_hash=False, auto_exc=False, eq=None, order=None, auto_detect=False, collect_by_mro=False, getstate_setstate=None, on_setattr=None, field_transformer=None, match_args=True)
2015-01-28 13:36:11 +00:00
2015-01-29 09:17:08 +00:00
.. note ::
2016-08-16 10:18:03 +00:00
`` attrs `` also comes with a serious business alias `` attr.attrs `` .
2015-01-29 09:17:08 +00:00
2015-02-08 11:32:32 +00:00
For example:
.. doctest ::
>>> import attr
>>> @attr.s
... class C(object):
... _private = attr.ib()
>>> C(private=42)
C(_private=42)
>>> class D(object):
... def __init__(self, x):
... self.x = x
>>> D(1)
<D object at ...>
2015-02-20 12:29:47 +00:00
>>> D = attr.s(these={"x": attr.ib()}, init=False)(D)
2015-02-08 11:32:32 +00:00
>>> D(1)
D(x=1)
2019-02-25 17:51:36 +00:00
>>> @attr.s(auto_exc=True)
... class Error(Exception):
... x = attr.ib()
... y = attr.ib(default=42, init=False)
>>> Error("foo")
Error(x='foo', y=42)
>>> raise Error("foo")
Traceback (most recent call last):
...
Error: ('foo', 42)
>>> raise ValueError("foo", 42) # for comparison
Traceback (most recent call last):
...
ValueError: ('foo', 42)
2015-02-08 11:32:32 +00:00
2015-01-28 13:36:11 +00:00
.. autofunction :: attr.ib
2015-01-29 09:17:08 +00:00
.. note ::
2016-08-16 10:18:03 +00:00
`` attrs `` also comes with a serious business alias `` attr.attrib `` .
2015-01-29 09:17:08 +00:00
2019-09-09 13:02:16 +00:00
The object returned by `attr.ib` also allows for setting the default and the validator using decorators:
2017-02-11 15:55:39 +00:00
2017-05-22 23:42:40 +00:00
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib()
... y = attr.ib()
... @x.validator
2019-06-17 07:17:29 +00:00
... def _any_name_except_a_name_of_an_attribute(self, attribute, value):
2017-05-22 23:42:40 +00:00
... if value < 0:
... raise ValueError("x must be positive")
... @y.default
2019-06-17 07:17:29 +00:00
... def _any_name_except_a_name_of_an_attribute(self):
2017-05-22 23:42:40 +00:00
... return self.x + 1
>>> C(1)
C(x=1, y=2)
>>> C(-1)
Traceback (most recent call last):
...
ValueError: x must be positive
2015-01-28 13:36:11 +00:00
2015-01-29 11:20:17 +00:00
.. autoclass :: attr.Attribute
2020-10-16 10:40:12 +00:00
:members: evolve
2015-01-30 07:57:33 +00:00
2021-10-06 10:21:36 +00:00
For example:
2015-01-29 11:20:17 +00:00
.. doctest ::
>>> import attr
>>> @attr.s
... class C(object):
... x = attr.ib()
2017-10-02 10:14:37 +00:00
>>> attr.fields(C).x
2021-02-22 07:48:34 +00:00
Attribute(name='x', default=NOTHING, validator=None, repr=True, eq=True, eq_key=None, order=True, order_key=None, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False, inherited=False, on_setattr=None)
2015-01-29 22:10:56 +00:00
2015-01-30 07:57:33 +00:00
.. autofunction :: attr.make_class
This is handy if you want to programmatically create classes.
For example:
.. doctest ::
>>> C1 = attr.make_class("C1", ["x", "y"])
>>> C1(1, 2)
C1(x=1, y=2)
>>> C2 = attr.make_class("C2", {"x": attr.ib(default=42),
... "y": attr.ib(default=attr.Factory(list))})
>>> C2()
C2(x=42, y=[])
2015-02-20 12:29:47 +00:00
2015-01-29 22:10:56 +00:00
.. autoclass :: attr.Factory
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib(default=attr.Factory(list))
2017-05-16 07:36:39 +00:00
... y = attr.ib(default=attr.Factory(
... lambda self: set(self.x),
... takes_self=True)
... )
2015-01-29 22:10:56 +00:00
>>> C()
2017-05-16 07:36:39 +00:00
C(x=[], y=set())
>>> C([1, 2, 3])
C(x=[1, 2, 3], y={1, 2, 3})
2015-01-29 11:20:17 +00:00
2020-01-06 11:34:58 +00:00
Exceptions
----------
.. autoexception :: attr.exceptions.PythonTooOldError
2020-07-20 10:43:10 +00:00
.. autoexception :: attr.exceptions.FrozenError
2016-08-20 16:45:15 +00:00
.. autoexception :: attr.exceptions.FrozenInstanceError
2020-07-20 10:43:10 +00:00
.. autoexception :: attr.exceptions.FrozenAttributeError
2016-09-10 17:14:34 +00:00
.. autoexception :: attr.exceptions.AttrsAttributeNotFoundError
.. autoexception :: attr.exceptions.NotAnAttrsClassError
2017-05-16 07:36:39 +00:00
.. autoexception :: attr.exceptions.DefaultAlreadySetError
2017-11-08 10:15:21 +00:00
.. autoexception :: attr.exceptions.UnannotatedAttributeError
2019-09-09 13:02:16 +00:00
.. autoexception :: attr.exceptions.NotCallableError
2017-11-08 10:15:21 +00:00
For example::
@attr.s(auto_attribs=True)
class C:
x: int
2018-05-01 10:18:26 +00:00
y = attr.ib() # <- ERROR!
2016-08-20 16:45:15 +00:00
2016-08-30 10:12:02 +00:00
.. _helpers:
2015-01-28 13:36:11 +00:00
Helpers
-------
2016-08-15 08:00:23 +00:00
`` attrs `` comes with a bunch of helper methods that make working with it easier:
2015-01-28 13:36:11 +00:00
2021-05-04 15:41:14 +00:00
.. autofunction :: attr.cmp_using
2015-01-29 20:55:25 +00:00
.. autofunction :: attr.fields
2015-01-28 13:36:11 +00:00
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib()
... y = attr.ib()
2015-01-29 20:55:25 +00:00
>>> attr.fields(C)
2021-02-22 07:48:34 +00:00
(Attribute(name='x', default=NOTHING, validator=None, repr=True, eq=True, eq_key=None, order=True, order_key=None, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False, inherited=False, on_setattr=None), Attribute(name='y', default=NOTHING, validator=None, repr=True, eq=True, eq_key=None, order=True, order_key=None, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False, inherited=False, on_setattr=None))
2016-09-10 17:55:27 +00:00
>>> attr.fields(C)[1]
2021-02-22 07:48:34 +00:00
Attribute(name='y', default=NOTHING, validator=None, repr=True, eq=True, eq_key=None, order=True, order_key=None, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False, inherited=False, on_setattr=None)
2016-09-10 17:55:27 +00:00
>>> attr.fields(C).y is attr.fields(C)[1]
True
2015-01-28 13:36:11 +00:00
2018-03-03 14:09:05 +00:00
.. autofunction :: attr.fields_dict
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib()
... y = attr.ib()
>>> attr.fields_dict(C)
2021-02-22 07:48:34 +00:00
{'x': Attribute(name='x', default=NOTHING, validator=None, repr=True, eq=True, eq_key=None, order=True, order_key=None, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False, inherited=False, on_setattr=None), 'y': Attribute(name='y', default=NOTHING, validator=None, repr=True, eq=True, eq_key=None, order=True, order_key=None, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False, inherited=False, on_setattr=None)}
2018-03-03 14:09:05 +00:00
>>> attr.fields_dict(C)['y']
2021-02-22 07:48:34 +00:00
Attribute(name='y', default=NOTHING, validator=None, repr=True, eq=True, eq_key=None, order=True, order_key=None, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False, inherited=False, on_setattr=None)
2018-03-03 14:09:05 +00:00
>>> attr.fields_dict(C)['y'] is attr.fields(C).y
True
2015-01-28 13:36:11 +00:00
.. autofunction :: attr.has
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... pass
>>> attr.has(C)
True
>>> attr.has(object)
False
2015-01-29 09:17:08 +00:00
2020-07-22 09:43:07 +00:00
.. autofunction :: attr.resolve_types
For example:
.. doctest ::
>>> import typing
>>> @attr.s(auto_attribs=True)
... class A:
... a: typing.List['A']
... b: 'B'
...
>>> @attr.s(auto_attribs=True)
... class B:
... a: A
...
>>> attr.fields(A).a.type
typing.List[ForwardRef('A')]
>>> attr.fields(A).b.type
'B'
>>> attr.resolve_types(A, globals(), locals())
<class 'A'>
>>> attr.fields(A).a.type
typing.List[A]
>>> attr.fields(A).b.type
<class 'B'>
2020-07-22 10:19:58 +00:00
.. autofunction :: attr.asdict
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib()
... y = attr.ib()
>>> attr.asdict(C(1, C(2, 3)))
{'x': 1, 'y': {'x': 2, 'y': 3}}
.. autofunction :: attr.astuple
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib()
... y = attr.ib()
>>> attr.astuple(C(1,2))
(1, 2)
`` attrs `` includes some handy helpers for filtering the attributes in `attr.asdict` and `attr.astuple` :
2015-02-20 15:34:21 +00:00
.. autofunction :: attr.filters.include
.. autofunction :: attr.filters.exclude
2019-09-09 13:02:16 +00:00
See :func: `asdict` for examples.
2015-02-20 15:34:21 +00:00
2017-01-21 16:11:45 +00:00
.. autofunction :: attr.evolve
2017-05-22 23:23:18 +00:00
For example:
2017-01-21 16:11:45 +00:00
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib()
... y = attr.ib()
>>> i1 = C(1, 2)
>>> i1
C(x=1, y=2)
>>> i2 = attr.evolve(i1, y=3)
>>> i2
C(x=1, y=3)
>>> i1 == i2
False
2017-05-22 23:23:18 +00:00
`` evolve `` creates a new instance using `` __init__ `` .
This fact has several implications:
2017-05-04 11:20:39 +00:00
2017-05-22 23:23:18 +00:00
* private attributes should be specified without the leading underscore, just like in `` __init__ `` .
* attributes with `` init=False `` can't be set with `` evolve `` .
* the usual `` __init__ `` validators will validate the new values.
2017-05-04 11:20:39 +00:00
2015-02-02 13:04:47 +00:00
.. autofunction :: validate
2015-02-02 11:13:11 +00:00
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib(validator=attr.validators.instance_of(int))
>>> i = C(1)
>>> i.x = "1"
2015-02-02 13:04:47 +00:00
>>> attr.validate(i)
2015-02-02 11:13:11 +00:00
Traceback (most recent call last):
...
2019-09-22 13:07:19 +00:00
TypeError: ("'x' must be <class 'int'> (got '1' that is a <class 'str'>).", ...)
2015-02-02 11:13:11 +00:00
2015-02-20 10:30:46 +00:00
Validators can be globally disabled if you want to run them only in development and tests but not in production because you fear their performance impact:
.. autofunction :: set_run_validators
.. autofunction :: get_run_validators
2015-01-29 11:20:17 +00:00
.. _api_validators:
Validators
----------
2016-08-15 08:00:23 +00:00
`` attrs `` comes with some common validators in the `` attrs.validators `` module:
2015-01-29 11:20:17 +00:00
2021-09-24 10:47:19 +00:00
.. autofunction :: attr.validators.lt
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib(validator=attr.validators.lt(42))
>>> C(41)
C(x=41)
>>> C(42)
Traceback (most recent call last):
...
ValueError: ("'x' must be < 42: 42")
.. autofunction :: attr.validators.le
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib(validator=attr.validators.le(42))
>>> C(42)
C(x=42)
>>> C(43)
Traceback (most recent call last):
...
ValueError: ("'x' must be <= 42: 43")
.. autofunction :: attr.validators.ge
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib(validator=attr.validators.ge(42))
>>> C(42)
C(x=42)
>>> C(41)
Traceback (most recent call last):
...
ValueError: ("'x' must be => 42: 41")
.. autofunction :: attr.validators.gt
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib(validator=attr.validators.gt(42))
>>> C(43)
C(x=43)
>>> C(42)
Traceback (most recent call last):
...
ValueError: ("'x' must be > 42: 42")
.. autofunction :: attr.validators.max_len
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib(validator=attr.validators.max_len(4))
>>> C("spam")
C(x='spam')
>>> C("bacon")
Traceback (most recent call last):
...
ValueError: ("Length of 'x' must be <= 4: 5")
2015-01-29 11:20:17 +00:00
.. autofunction :: attr.validators.instance_of
2015-01-28 13:36:11 +00:00
2015-01-29 11:20:17 +00:00
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib(validator=attr.validators.instance_of(int))
>>> C(42)
C(x=42)
>>> C("42")
Traceback (most recent call last):
...
2018-08-11 04:40:01 +00:00
TypeError: ("'x' must be <type 'int'> (got '42' that is a <type 'str'>).", Attribute(name='x', default=NOTHING, validator=<instance_of validator for type <type 'int'>>, type=None, kw_only=False), <type 'int'>, '42')
2015-07-09 23:14:32 +00:00
>>> C(None)
Traceback (most recent call last):
...
2018-08-11 04:40:01 +00:00
TypeError: ("'x' must be <type 'int'> (got None that is a <type 'NoneType'>).", Attribute(name='x', default=NOTHING, validator=<instance_of validator for type <type 'int'>>, repr=True, cmp=True, hash=None, init=True, type=None, kw_only=False), <type 'int'>, None)
2015-01-29 18:04:23 +00:00
2017-05-16 08:36:42 +00:00
.. autofunction :: attr.validators.in_
For example:
.. doctest ::
>>> import enum
>>> class State(enum.Enum):
... ON = "on"
... OFF = "off"
>>> @attr.s
... class C(object):
... state = attr.ib(validator=attr.validators.in_(State))
... val = attr.ib(validator=attr.validators.in_([1, 2, 3]))
>>> C(State.ON, 1)
C(state=<State.ON: 'on'>, val=1)
>>> C("on", 1)
Traceback (most recent call last):
...
ValueError: 'state' must be in <enum 'State'> (got 'on')
>>> C(State.ON, 4)
Traceback (most recent call last):
...
ValueError: 'val' must be in [1, 2, 3] (got 4)
.. autofunction :: attr.validators.provides
2017-05-12 21:02:07 +00:00
.. autofunction :: attr.validators.and_
2019-09-09 13:02:16 +00:00
For convenience, it's also possible to pass a list to `attr.ib` 's validator argument.
2017-05-12 21:02:07 +00:00
Thus the following two statements are equivalent::
x = attr.ib(validator=attr.validators.and_(v1, v2, v3))
x = attr.ib(validator=[v1, v2, v3])
2015-01-29 18:04:23 +00:00
2015-07-09 23:14:32 +00:00
.. autofunction :: attr.validators.optional
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(int)))
>>> C(42)
C(x=42)
>>> C("42")
Traceback (most recent call last):
...
2018-08-11 04:40:01 +00:00
TypeError: ("'x' must be <type 'int'> (got '42' that is a <type 'str'>).", Attribute(name='x', default=NOTHING, validator=<instance_of validator for type <type 'int'>>, type=None, kw_only=False), <type 'int'>, '42')
2015-07-09 23:14:32 +00:00
>>> C(None)
C(x=None)
2016-08-16 10:18:03 +00:00
2018-11-08 03:33:52 +00:00
.. autofunction :: attr.validators.is_callable
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib(validator=attr.validators.is_callable())
>>> C(isinstance)
C(x=<built-in function isinstance>)
>>> C("not a callable")
Traceback (most recent call last):
...
2019-07-20 09:55:26 +00:00
attr.exceptions.NotCallableError: 'x' must be callable (got 'not a callable' that is a <class 'str'>).
2018-11-08 03:33:52 +00:00
2019-09-09 08:48:52 +00:00
.. autofunction :: attr.validators.matches_re
For example:
.. doctest ::
>>> @attr.s
... class User(object):
... email = attr.ib(validator=attr.validators.matches_re(
... "(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)"))
>>> User(email="user@example.com")
User(email='user@example.com')
>>> User(email="user@example.com@test.com")
Traceback (most recent call last):
...
ValueError: ("'email' must match regex '(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\\\.[a-zA-Z0-9-.]+$)' ('user@example.com@test.com' doesn't)", Attribute(name='email', default=NOTHING, validator=<matches_re validator for pattern re.compile('(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$)')>, repr=True, cmp=True, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False), re.compile('(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$)'), 'user@example.com@test.com')
2018-11-08 03:33:52 +00:00
.. autofunction :: attr.validators.deep_iterable
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib(validator=attr.validators.deep_iterable(
... member_validator=attr.validators.instance_of(int),
... iterable_validator=attr.validators.instance_of(list)
... ))
>>> C(x=[1, 2, 3])
C(x=[1, 2, 3])
>>> C(x=set([1, 2, 3]))
Traceback (most recent call last):
...
TypeError: ("'x' must be <class 'list'> (got {1, 2, 3} that is a <class 'set'>).", Attribute(name='x', default=NOTHING, validator=<deep_iterable validator for <instance_of validator for type <class 'list'>> iterables of <instance_of validator for type <class 'int'>>>, repr=True, cmp=True, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False), <class 'list'>, {1, 2, 3})
>>> C(x=[1, 2, "3"])
Traceback (most recent call last):
...
TypeError: ("'x' must be <class 'int'> (got '3' that is a <class 'str'>).", Attribute(name='x', default=NOTHING, validator=<deep_iterable validator for <instance_of validator for type <class 'list'>> iterables of <instance_of validator for type <class 'int'>>>, repr=True, cmp=True, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False), <class 'int'>, '3')
.. autofunction :: attr.validators.deep_mapping
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib(validator=attr.validators.deep_mapping(
... key_validator=attr.validators.instance_of(str),
... value_validator=attr.validators.instance_of(int),
... mapping_validator=attr.validators.instance_of(dict)
... ))
>>> C(x={"a": 1, "b": 2})
C(x={'a': 1, 'b': 2})
>>> C(x=None)
Traceback (most recent call last):
...
TypeError: ("'x' must be <class 'dict'> (got None that is a <class 'NoneType'>).", Attribute(name='x', default=NOTHING, validator=<deep_mapping validator for objects mapping <instance_of validator for type <class 'str'>> to <instance_of validator for type <class 'int'>>>, repr=True, cmp=True, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False), <class 'dict'>, None)
>>> C(x={"a": 1.0, "b": 2})
Traceback (most recent call last):
...
TypeError: ("'x' must be <class 'int'> (got 1.0 that is a <class 'float'>).", Attribute(name='x', default=NOTHING, validator=<deep_mapping validator for objects mapping <instance_of validator for type <class 'str'>> to <instance_of validator for type <class 'int'>>>, repr=True, cmp=True, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False), <class 'int'>, 1.0)
>>> C(x={"a": 1, 7: 2})
Traceback (most recent call last):
...
TypeError: ("'x' must be <class 'str'> (got 7 that is a <class 'int'>).", Attribute(name='x', default=NOTHING, validator=<deep_mapping validator for objects mapping <instance_of validator for type <class 'str'>> to <instance_of validator for type <class 'int'>>>, repr=True, cmp=True, hash=None, init=True, metadata=mappingproxy({}), type=None, converter=None, kw_only=False), <class 'str'>, 7)
2021-11-17 06:05:01 +00:00
Validators can be both globally and locally disabled:
.. autofunction :: attr.validators.set_disabled
.. autofunction :: attr.validators.get_disabled
.. autofunction :: attr.validators.disabled
2018-11-08 03:33:52 +00:00
2017-05-10 13:37:50 +00:00
Converters
----------
2020-07-21 12:43:09 +00:00
.. autofunction :: attr.converters.pipe
2020-03-05 10:54:44 +00:00
For convenience, it's also possible to pass a list to `attr.ib` 's converter argument.
Thus the following two statements are equivalent::
2020-07-21 12:43:09 +00:00
x = attr.ib(converter=attr.converter.pipe(c1, c2, c3))
2020-03-05 10:54:44 +00:00
x = attr.ib(converter=[c1, c2, c3])
2017-05-10 13:37:50 +00:00
.. autofunction :: attr.converters.optional
For example:
.. doctest ::
>>> @attr.s
... class C(object):
2017-12-23 07:46:10 +00:00
... x = attr.ib(converter=attr.converters.optional(int))
2017-05-10 13:37:50 +00:00
>>> C(None)
C(x=None)
>>> C(42)
C(x=42)
2018-07-28 15:03:41 +00:00
.. autofunction :: attr.converters.default_if_none
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib(
... converter=attr.converters.default_if_none("")
... )
>>> C(None)
C(x='')
2021-08-10 05:45:28 +00:00
.. autofunction :: attr.converters.to_bool
For example:
.. doctest ::
>>> @attr.s
... class C(object):
... x = attr.ib(
... converter=attr.converters.to_bool
... )
>>> C("yes")
C(x=True)
>>> C(0)
C(x=False)
>>> C("foo")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Cannot convert value to bool: foo
2020-07-20 10:43:10 +00:00
.. _api_setters:
Setters
-------
These are helpers that you can use together with `attr.s` 's and `attr.ib` 's `` on_setattr `` arguments.
.. autofunction :: attr.setters.frozen
.. autofunction :: attr.setters.validate
.. autofunction :: attr.setters.convert
.. autofunction :: attr.setters.pipe
.. autodata :: attr.setters.NO_OP
For example, only `` x `` is frozen here:
.. doctest ::
>>> @attr.s(on_setattr=attr.setters.frozen)
... class C(object):
... x = attr.ib()
... y = attr.ib(on_setattr=attr.setters.NO_OP)
>>> c = C(1, 2)
>>> c.y = 3
>>> c.y
3
>>> c.x = 4
Traceback (most recent call last):
...
attr.exceptions.FrozenAttributeError: ()
N.B. Please use `attr.s` 's *frozen* argument to freeze whole classes; it is more efficient.
2021-04-09 18:36:10 +00:00
.. _next-gen:
2020-08-17 14:22:33 +00:00
2021-04-09 18:36:10 +00:00
Next Generation APIs
--------------------
2020-08-17 14:22:33 +00:00
2021-04-09 18:36:10 +00:00
These are Python 3.6 and later-only, and keyword-only APIs that call `attr.s` with different default values.
2020-08-17 14:22:33 +00:00
The most notable differences are:
- automatically detect whether or not *auto_attribs* should be `True`
2020-09-28 10:27:37 +00:00
- *slots=True* (see :term: `slotted classes` for potentially surprising behaviors)
2020-08-17 14:22:33 +00:00
- *auto_exc=True*
- *auto_detect=True*
- *eq=True* , but *order=False*
2021-12-14 14:50:37 +00:00
- Converters and validators are run when you set an attribute (*on_setattr=[attr.setters.convert, attr.setters.validate* ]).
2020-08-17 14:22:33 +00:00
- Some options that aren't relevant to Python 3 have been dropped.
Please note that these are *defaults* and you're free to override them, just like before.
2021-04-09 18:36:10 +00:00
Since the Python ecosystem has settled on the term `` field `` for defining attributes, we have also added `attr.field` as a substitute for `attr.ib` .
2020-08-17 14:22:33 +00:00
2021-12-14 14:50:37 +00:00
.. versionchanged :: 21.3.0 Converters are also run `` on_setattr `` .
2020-08-17 14:22:33 +00:00
.. note ::
`attr.s` and `attr.ib` (and their serious business cousins) aren't going anywhere.
The new APIs build on top of them.
.. autofunction :: attr.define
2021-10-12 05:42:46 +00:00
.. function :: mutable(same_as_define)
2020-08-17 14:22:33 +00:00
Alias for `attr.define` .
2020-08-20 17:01:34 +00:00
.. versionadded :: 20.1.0
2021-10-12 05:42:46 +00:00
.. function :: frozen(same_as_define)
2020-08-17 14:22:33 +00:00
Behaves the same as `attr.define` but sets *frozen=True* and *on_setattr=None* .
2020-08-20 17:01:34 +00:00
.. versionadded :: 20.1.0
.. autofunction :: attr.field
2020-08-17 14:22:33 +00:00
2016-08-16 10:18:03 +00:00
Deprecated APIs
---------------
2019-10-01 14:06:36 +00:00
.. _version-info:
To help you write backward compatible code that doesn't throw warnings on modern releases, the `` attr `` module has an `` __version_info__ `` attribute as of version 19.2.0.
It behaves similarly to `sys.version_info` and is an instance of `VersionInfo` :
.. autoclass :: VersionInfo
With its help you can write code like this:
>>> if getattr(attr, "__version_info__", (0,)) >= (19, 2):
... cmp_off = {"eq": False}
... else:
... cmp_off = {"cmp": False}
>>> cmp_off == {"eq": False}
True
>>> @attr.s(**cmp_off)
... class C(object):
... pass
----
2016-08-16 10:18:03 +00:00
The serious business aliases used to be called `` attr.attributes `` and `` attr.attr `` .
There are no plans to remove them but they shouldn't be used in new code.
2017-02-03 10:03:16 +00:00
.. autofunction :: assoc