2017-10-26 15:55:45 +00:00
API Reference
=============
2015-01-28 13:36:11 +00:00
2023-01-02 15:27:37 +00:00
.. module :: attrs
2023-01-10 16:53:28 +00:00
*attrs* works by decorating a class using `attrs.define` or `attr.s` and then defining attributes on the class using `attrs.field` , `attr.ib` , or type annotations.
2015-01-28 13:36:11 +00:00
2024-08-02 06:03:14 +00:00
What follows is the dry API explanation for people who understand how *attrs* works.
If you'd like a hands-on tutorial, have a look at `examples` .
2015-01-28 13:36:11 +00:00
2023-01-10 16:53:28 +00:00
If you're confused by the many names, please check out `names` for clarification, but the `TL;DR <https://en.wikipedia.org/wiki/TL;DR> `_ is that as of version 21.3.0, *attrs* consists of **two** top-level package names:
2015-01-28 15:02:18 +00:00
2023-01-10 16:53:28 +00:00
- The classic `` attr `` that powers the venerable `attr.s` and `attr.ib` .
- The newer `` attrs `` that only contains most modern APIs and relies on `attrs.define` and `attrs.field` to define your classes.
2024-08-02 06:03:14 +00:00
Additionally, some of the APIs that also exist in `` attr `` have nicer defaults (for example, `attrs.asdict` ).
2021-12-25 14:15:10 +00:00
2023-01-10 16:53:28 +00:00
The `` attrs `` namespace is built *on top of* `` attr `` -- which will *never* go away -- and is just as stable, since it doesn't constitute a rewrite.
2024-08-02 06:03:14 +00:00
To keep repetition low and this document at a reasonable size, the `` attr `` namespace is `documented on a separate page <api-attr>` .
2021-12-25 14:15:10 +00:00
2015-01-28 13:36:11 +00:00
Core
----
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.define
2023-01-10 16:53:28 +00:00
.. function :: mutable(same_as_define)
2020-08-17 14:22:33 +00:00
2023-01-10 16:53:28 +00:00
Same as `attrs.define` .
2021-12-25 14:15:10 +00:00
.. versionadded :: 20.1.0
2023-01-10 16:53:28 +00:00
.. function :: frozen(same_as_define)
2021-12-25 14:15:10 +00:00
Behaves the same as `attrs.define` but sets *frozen=True* and *on_setattr=None* .
.. versionadded :: 20.1.0
2020-08-17 14:22:33 +00:00
2023-01-10 16:53:28 +00:00
.. autofunction :: field
2021-12-25 14:15:10 +00:00
2023-01-10 16:53:28 +00:00
.. autoclass :: Attribute
2021-12-25 14:15:10 +00:00
:members: evolve
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> import attrs
>>> from attrs import define, field
>>> @define
2022-03-21 09:35:44 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field()
>>> attrs.fields(C).x
2022-11-30 14:39:57 +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, alias='x')
2021-12-25 14:15:10 +00:00
2023-01-10 16:53:28 +00:00
.. autofunction :: make_class
2021-12-25 14:15:10 +00:00
This is handy if you want to programmatically create classes.
For example:
.. doctest ::
2023-01-02 07:50:57 +00:00
>>> C1 = attrs.make_class("C1", ["x", "y"])
2021-12-25 14:15:10 +00:00
>>> C1(1, 2)
C1(x=1, y=2)
2023-01-02 07:50:57 +00:00
>>> C2 = attrs.make_class("C2", {
2023-01-10 16:53:28 +00:00
... "x": field(default=42),
... "y": field(factory=list)
2023-01-02 07:50:57 +00:00
... })
2021-12-25 14:15:10 +00:00
>>> C2()
C2(x=42, y=[])
2023-01-10 16:53:28 +00:00
.. autoclass :: Factory
2021-12-25 14:15:10 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2022-03-21 09:35:44 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field(default=attrs.Factory(list))
... y = field(default=attrs.Factory(
2021-12-25 14:15:10 +00:00
... lambda self: set(self.x),
... takes_self=True)
... )
>>> C()
C(x=[], y=set())
>>> C([1, 2, 3])
C(x=[1, 2, 3], y={1, 2, 3})
2024-08-02 06:03:14 +00:00
.. autodata :: attrs.NOTHING
:no-value:
2021-12-25 14:15:10 +00:00
Exceptions
----------
2015-01-29 22:10:56 +00:00
2023-01-10 16:53:28 +00:00
.. module :: attrs.exceptions
2021-12-25 14:15:10 +00:00
All exceptions are available from both `` attr.exceptions `` and `` attrs.exceptions `` and are the same thing.
That means that it doesn't matter from from which namespace they've been raised and/or caught:
2015-01-29 11:20:17 +00:00
2021-12-25 14:15:10 +00:00
.. doctest ::
2015-01-29 11:20:17 +00:00
2021-12-25 14:15:10 +00:00
>>> import attrs, attr
>>> try:
... raise attrs.exceptions.FrozenError()
... except attr.exceptions.FrozenError:
... print("this works!")
this works!
2020-01-06 11:34:58 +00:00
2023-01-10 16:53:28 +00:00
.. autoexception :: PythonTooOldError
.. autoexception :: FrozenError
.. autoexception :: FrozenInstanceError
.. autoexception :: FrozenAttributeError
.. autoexception :: AttrsAttributeNotFoundError
.. autoexception :: NotAnAttrsClassError
.. autoexception :: DefaultAlreadySetError
.. autoexception :: NotCallableError
.. autoexception :: UnannotatedAttributeError
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
-------
2022-12-20 09:17:48 +00:00
*attrs* comes with a bunch of helper methods that make working with it easier:
2015-01-28 13:36:11 +00:00
2023-01-10 16:53:28 +00:00
.. currentmodule :: attrs
2021-12-25 14:15:10 +00:00
2023-01-10 16:53:28 +00:00
.. autofunction :: attrs.cmp_using
2021-05-04 15:41:14 +00:00
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.fields
2015-01-28 13:36:11 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2022-03-21 09:35:44 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field()
... y = field()
2021-12-25 14:15:10 +00:00
>>> attrs.fields(C)
2022-11-30 14:39:57 +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, alias='x'), 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, alias='y'))
2021-12-25 14:15:10 +00:00
>>> attrs.fields(C)[1]
2022-11-30 14:39:57 +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, alias='y')
2021-12-25 14:15:10 +00:00
>>> attrs.fields(C).y is attrs.fields(C)[1]
2016-09-10 17:55:27 +00:00
True
2015-01-28 13:36:11 +00:00
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.fields_dict
2018-03-03 14:09:05 +00:00
For example:
.. doctest ::
>>> @attr.s
2022-03-21 09:35:44 +00:00
... class C:
2018-03-03 14:09:05 +00:00
... x = attr.ib()
... y = attr.ib()
2021-12-25 14:15:10 +00:00
>>> attrs.fields_dict(C)
2022-11-30 14:39:57 +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, alias='x'), '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, alias='y')}
2018-03-03 14:09:05 +00:00
>>> attr.fields_dict(C)['y']
2022-11-30 14:39:57 +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, alias='y')
2021-12-25 14:15:10 +00:00
>>> attrs.fields_dict(C)['y'] is attrs.fields(C).y
2018-03-03 14:09:05 +00:00
True
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.has
2015-01-28 13:36:11 +00:00
For example:
.. doctest ::
>>> @attr.s
2022-03-21 09:35:44 +00:00
... class C:
2015-01-28 13:36:11 +00:00
... pass
>>> attr.has(C)
True
>>> attr.has(object)
False
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.resolve_types
2020-07-22 09:43:07 +00:00
For example:
.. doctest ::
>>> import typing
2023-01-10 16:53:28 +00:00
>>> @define
2020-07-22 09:43:07 +00:00
... class A:
... a: typing.List['A']
... b: 'B'
...
2023-01-10 16:53:28 +00:00
>>> @define
2020-07-22 09:43:07 +00:00
... class B:
... a: A
...
2021-12-25 14:15:10 +00:00
>>> attrs.fields(A).a.type
2020-07-22 09:43:07 +00:00
typing.List[ForwardRef('A')]
2021-12-25 14:15:10 +00:00
>>> attrs.fields(A).b.type
2020-07-22 09:43:07 +00:00
'B'
2021-12-25 14:15:10 +00:00
>>> attrs.resolve_types(A, globals(), locals())
2020-07-22 09:43:07 +00:00
<class 'A'>
2021-12-25 14:15:10 +00:00
>>> attrs.fields(A).a.type
2020-07-22 09:43:07 +00:00
typing.List[A]
2021-12-25 14:15:10 +00:00
>>> attrs.fields(A).b.type
2020-07-22 09:43:07 +00:00
<class 'B'>
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.asdict
2020-07-22 10:19:58 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2021-12-25 14:15:10 +00:00
... class C:
... x: int
... y: int
>>> attrs.asdict(C(1, C(2, 3)))
2020-07-22 10:19:58 +00:00
{'x': 1, 'y': {'x': 2, 'y': 3}}
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.astuple
2020-07-22 10:19:58 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2021-12-25 14:15:10 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field()
... y = field()
2021-12-25 14:15:10 +00:00
>>> attrs.astuple(C(1,2))
2020-07-22 10:19:58 +00:00
(1, 2)
2023-01-10 16:53:28 +00:00
.. module :: attrs.filters
2021-12-25 14:15:10 +00:00
2023-01-10 16:53:28 +00:00
*attrs* includes helpers for filtering the attributes in `attrs.asdict` and `attrs.astuple` :
2021-12-25 14:15:10 +00:00
2023-01-10 16:53:28 +00:00
.. autofunction :: include
2021-12-25 14:15:10 +00:00
2023-01-10 16:53:28 +00:00
.. autofunction :: exclude
2015-02-20 15:34:21 +00:00
2021-12-25 14:15:10 +00:00
See :func: `attrs.asdict` for examples.
2015-02-20 15:34:21 +00:00
2023-01-10 16:53:28 +00:00
All objects from `` attrs.filters `` are also available from `` attr.filters `` (it's the same module in a different namespace).
2015-02-20 15:34:21 +00:00
2021-12-25 14:15:10 +00:00
----
2023-01-10 16:53:28 +00:00
.. currentmodule :: attrs
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.evolve
2017-01-21 16:11:45 +00:00
2017-05-22 23:23:18 +00:00
For example:
2017-01-21 16:11:45 +00:00
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2021-12-25 14:15:10 +00:00
... class C:
... x: int
... y: int
2017-01-21 16:11:45 +00:00
>>> i1 = C(1, 2)
>>> i1
C(x=1, y=2)
2021-12-25 14:15:10 +00:00
>>> i2 = attrs.evolve(i1, y=3)
2017-01-21 16:11:45 +00:00
>>> 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
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validate
2015-02-02 11:13:11 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define(on_setattr=attrs.setters.NO_OP)
2021-12-25 14:15:10 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field(validator=attrs.validators.instance_of(int))
2015-02-02 11:13:11 +00:00
>>> i = C(1)
>>> i.x = "1"
2021-12-25 14:15:10 +00:00
>>> attrs.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
2022-12-20 07:22:51 +00:00
.. _api-validators:
2015-01-29 11:20:17 +00:00
Validators
----------
2023-01-10 16:53:28 +00:00
.. module :: attrs.validators
2015-01-29 11:20:17 +00:00
2023-01-10 16:53:28 +00:00
*attrs* comes with some common validators in the `` attrs.validators `` module.
All objects from `` attrs.validators `` are also available from `` attr.validators `` (it's the same module in a different namespace).
2015-01-29 11:20:17 +00:00
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.lt
2021-09-24 10:47:19 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2021-12-25 14:15:10 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field(validator=attrs.validators.lt(42))
2021-09-24 10:47:19 +00:00
>>> C(41)
C(x=41)
>>> C(42)
Traceback (most recent call last):
...
ValueError: ("'x' must be < 42: 42")
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.le
2021-09-24 10:47:19 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2022-03-21 09:35:44 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field(validator=attrs.validators.le(42))
2021-09-24 10:47:19 +00:00
>>> C(42)
C(x=42)
>>> C(43)
Traceback (most recent call last):
...
ValueError: ("'x' must be <= 42: 43")
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.ge
2021-09-24 10:47:19 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2021-12-25 14:15:10 +00:00
... class C:
... x = attrs.field(validator=attrs.validators.ge(42))
2021-09-24 10:47:19 +00:00
>>> C(42)
C(x=42)
>>> C(41)
Traceback (most recent call last):
...
ValueError: ("'x' must be => 42: 41")
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.gt
2021-09-24 10:47:19 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2021-12-25 14:15:10 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field(validator=attrs.validators.gt(42))
2021-09-24 10:47:19 +00:00
>>> C(43)
C(x=43)
>>> C(42)
Traceback (most recent call last):
...
ValueError: ("'x' must be > 42: 42")
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.max_len
2021-09-24 10:47:19 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2021-12-25 14:15:10 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field(validator=attrs.validators.max_len(4))
2021-09-24 10:47:19 +00:00
>>> C("spam")
C(x='spam')
>>> C("bacon")
Traceback (most recent call last):
...
ValueError: ("Length of 'x' must be <= 4: 5")
2022-02-02 09:10:33 +00:00
.. autofunction :: attrs.validators.min_len
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2022-02-02 09:10:33 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field(validator=attrs.validators.min_len(1))
2022-02-02 09:10:33 +00:00
>>> C("bacon")
C(x='bacon')
>>> C("")
Traceback (most recent call last):
...
ValueError: ("Length of 'x' must be => 1: 0")
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.instance_of
2015-01-28 13:36:11 +00:00
2015-01-29 11:20:17 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2021-12-25 14:15:10 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field(validator=attrs.validators.instance_of(int))
2015-01-29 11:20:17 +00:00
>>> 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
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.in_
2017-05-16 08:36:42 +00:00
For example:
.. doctest ::
2022-06-13 06:33:23 +00:00
>>> import enum
>>> class State(enum.Enum):
... ON = "on"
... OFF = "off"
2023-01-10 16:53:28 +00:00
>>> @define
2022-06-13 06:33:23 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... state = field(validator=attrs.validators.in_(State))
... val = field(validator=attrs.validators.in_([1, 2, 3]))
2022-06-13 06:33:23 +00:00
>>> C(State.ON, 1)
C(state=<State.ON: 'on'>, val=1)
2023-11-28 12:16:17 +00:00
>>> C("On", 1)
2022-06-13 06:33:23 +00:00
Traceback (most recent call last):
...
2023-11-28 12:16:17 +00:00
ValueError: 'state' must be in <enum 'State'> (got 'On'), Attribute(name='state', default=NOTHING, validator=<in_ validator with options <enum 'State'>>, 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), <enum 'State'>, 'on')
2022-06-13 06:33:23 +00:00
>>> C(State.ON, 4)
Traceback (most recent call last):
...
ValueError: 'val' must be in [1, 2, 3] (got 4), Attribute(name='val', default=NOTHING, validator=<in_ validator with options [1, 2, 3]>, 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), [1, 2, 3], 4)
2017-05-16 08:36:42 +00:00
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.and_
2017-05-12 21:02:07 +00:00
2021-12-25 14:15:10 +00:00
For convenience, it's also possible to pass a list to `attrs.field` 's validator argument.
2017-05-12 21:02:07 +00:00
Thus the following two statements are equivalent::
2023-01-10 16:53:28 +00:00
x = field(validator=attrs.validators.and_(v1, v2, v3))
x = field(validator=[v1, v2, v3])
2015-01-29 18:04:23 +00:00
2024-07-17 12:01:41 +00:00
.. autofunction :: attrs.validators.or_
For example:
.. doctest ::
>>> @define
... class C:
... val: int | list[int] = field(
... validator=attrs.validators.or_(
... attrs.validators.instance_of(int),
... attrs.validators.deep_iterable(attrs.validators.instance_of(int)),
... )
... )
>>> C(42)
C(val=42)
>>> C([1, 2, 3])
C(val=[1, 2, 3])
>>> C(val='42')
Traceback (most recent call last):
...
ValueError: None of (<instance_of validator for type <class 'int'>>, <deep_iterable validator for iterables of <instance_of validator for type <class 'int'>>>) satisfied for value '42'
2022-09-04 11:55:02 +00:00
.. autofunction :: attrs.validators.not_
For example:
.. doctest ::
>>> reserved_names = {"id", "time", "source"}
2023-01-10 16:53:28 +00:00
>>> @define
2022-09-04 11:55:02 +00:00
... class Measurement:
2023-01-10 16:53:28 +00:00
... tags = field(
2022-09-04 11:55:02 +00:00
... validator=attrs.validators.deep_mapping(
... key_validator=attrs.validators.not_(
... attrs.validators.in_(reserved_names),
... msg="reserved tag key",
... ),
... value_validator=attrs.validators.instance_of((str, int)),
... )
... )
>>> Measurement(tags={"source": "universe"})
Traceback (most recent call last):
...
ValueError: ("reserved tag key", Attribute(name='tags', default=NOTHING, validator=<not_ validator wrapping <in_ validator with options {'id', 'time', 'source'}>, capturing (<class 'ValueError'>, <class 'TypeError'>)>, type=None, kw_only=False), <in_ validator with options {'id', 'time', 'source'}>, {'source_': 'universe'}, (<class 'ValueError'>, <class 'TypeError'>))
>>> Measurement(tags={"source_": "universe"})
Measurement(tags={'source_': 'universe'})
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.optional
2015-07-09 23:14:32 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2021-12-25 14:15:10 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field(
... validator=attrs.validators.optional(
... attrs.validators.instance_of(int)
... ))
2015-07-09 23:14:32 +00:00
>>> 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
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.is_callable
2018-11-08 03:33:52 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2021-12-25 14:15:10 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field(validator=attrs.validators.is_callable())
2018-11-08 03:33:52 +00:00
>>> 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
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.matches_re
2019-09-09 08:48:52 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2021-12-25 14:15:10 +00:00
... class User:
2023-01-10 16:53:28 +00:00
... email = field(validator=attrs.validators.matches_re(
2023-11-28 12:16:17 +00:00
... r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)"))
2019-09-09 08:48:52 +00:00
>>> 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')
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.deep_iterable
2018-11-08 03:33:52 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2021-12-25 14:15:10 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field(validator=attrs.validators.deep_iterable(
... member_validator=attrs.validators.instance_of(int),
... iterable_validator=attrs.validators.instance_of(list)
2018-11-08 03:33:52 +00:00
... ))
>>> 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')
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.deep_mapping
2018-11-08 03:33:52 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2021-12-25 14:15:10 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field(validator=attrs.validators.deep_mapping(
... key_validator=attrs.validators.instance_of(str),
... value_validator=attrs.validators.instance_of(int),
... mapping_validator=attrs.validators.instance_of(dict)
2018-11-08 03:33:52 +00:00
... ))
>>> 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:
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.set_disabled
2021-11-17 06:05:01 +00:00
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.get_disabled
2021-11-17 06:05:01 +00:00
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.validators.disabled
2021-11-17 06:05:01 +00:00
2018-11-08 03:33:52 +00:00
2017-05-10 13:37:50 +00:00
Converters
----------
2024-07-28 13:55:24 +00:00
.. autoclass :: attrs.Converter
For example:
.. doctest ::
>>> def complicated(value, self_, field):
... return int(value) * self_.factor + field.metadata["offset"]
>>> @define
... class C:
... factor = 5 # not an *attrs* field
... x = field(
... metadata={"offset": 200},
... converter=attrs.Converter(
... complicated,
... takes_self=True, takes_field=True
... ))
>>> C("42")
C(x=410)
2023-01-10 16:53:28 +00:00
.. module :: attrs.converters
All objects from `` attrs.converters `` are also available from `` attr.converters `` (it's the same module in a different namespace).
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.converters.pipe
2020-03-05 10:54:44 +00:00
2023-01-10 16:53:28 +00:00
For convenience, it's also possible to pass a list to `attrs.field` / `attr.ib` 's converter arguments.
2020-03-05 10:54:44 +00:00
Thus the following two statements are equivalent::
2023-01-10 16:53:28 +00:00
x = attrs.field(converter=attrs.converter.pipe(c1, c2, c3))
x = attrs.field(converter=[c1, c2, c3])
2020-03-05 10:54:44 +00:00
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.converters.optional
2017-05-10 13:37:50 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2022-03-21 09:35:44 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field(converter=attrs.converters.optional(int))
2017-05-10 13:37:50 +00:00
>>> C(None)
C(x=None)
>>> C(42)
C(x=42)
2021-12-25 14:15:10 +00:00
.. autofunction :: attrs.converters.default_if_none
2018-07-28 15:03:41 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2022-03-21 09:35:44 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field(
... converter=attrs.converters.default_if_none("")
2018-07-28 15:03:41 +00:00
... )
>>> C(None)
C(x='')
2024-03-17 08:04:48 +00:00
.. autofunction :: attrs.converters.to_bool(val)
2021-08-10 05:45:28 +00:00
For example:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define
2022-03-21 09:35:44 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field(
... converter=attrs.converters.to_bool
2021-08-10 05:45:28 +00:00
... )
>>> C("yes")
C(x=True)
>>> C(0)
C(x=False)
2024-03-17 08:04:48 +00:00
>>> C("norway")
2021-08-10 05:45:28 +00:00
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
2024-03-17 08:04:48 +00:00
ValueError: Cannot convert value to bool: norway
2021-08-10 05:45:28 +00:00
2020-07-20 10:43:10 +00:00
.. _api_setters:
Setters
-------
2023-01-10 16:53:28 +00:00
.. module :: attrs.setters
2024-01-12 08:38:07 +00:00
These are helpers that you can use together with `attrs.define` 's and `attrs.field` 's `` on_setattr `` arguments.
2023-01-10 16:53:28 +00:00
All setters in `` attrs.setters `` are also available from `` attr.setters `` (it's the same module in a different namespace).
.. autofunction :: frozen
.. autofunction :: validate
.. autofunction :: convert
.. autofunction :: pipe
2020-07-20 10:43:10 +00:00
2023-01-10 16:53:28 +00:00
.. data :: NO_OP
2022-02-02 07:21:53 +00:00
Sentinel for disabling class-wide *on_setattr* hooks for certain attributes.
Does not work in `attrs.setters.pipe` or within lists.
.. versionadded :: 20.1.0
2020-07-20 10:43:10 +00:00
For example, only `` x `` is frozen here:
.. doctest ::
2023-01-10 16:53:28 +00:00
>>> @define(on_setattr=attr.setters.frozen)
2021-12-25 14:15:10 +00:00
... class C:
2023-01-10 16:53:28 +00:00
... x = field()
... y = field(on_setattr=attr.setters.NO_OP)
2020-07-20 10:43:10 +00:00
>>> c = C(1, 2)
>>> c.y = 3
>>> c.y
3
>>> c.x = 4
Traceback (most recent call last):
...
2021-12-25 14:15:10 +00:00
attrs.exceptions.FrozenAttributeError: ()
2020-08-20 17:01:34 +00:00
2024-03-17 07:07:39 +00:00
.. tip ::
Use `attrs.define` 's *frozen* argument (or `attrs.frozen` ) to freeze whole classes; it is more efficient.