API Reference¶
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.
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 attrs by Example.
If you’re confused by the many names, please check out On The Core API Names for clarification, but the TL;DR is that as of version 21.3.0, attrs consists of two top-level package names:
The classic
attr
that powers the venerableattr.s
andattr.ib
.The newer
attrs
that only contains most modern APIs and relies onattrs.define
andattrs.field
to define your classes. Additionally, some of the APIs that also exist inattr
have nicer defaults (for example,attrs.asdict
).
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.
To keep repetition low and this document at a reasonable size, the attr
namespace is documented on a separate page.
Core¶
- attrs.define(maybe_cls=None, *, these=None, repr=None, unsafe_hash=None, hash=None, init=None, slots=True, frozen=False, weakref_slot=True, str=False, auto_attribs=None, kw_only=False, cache_hash=False, auto_exc=True, eq=None, order=False, auto_detect=True, getstate_setstate=None, on_setattr=None, field_transformer=None, match_args=True)¶
A class decorator that adds dunder methods according to fields specified using type annotations,
field()
calls, or the these argument.Since attrs patches or replaces an existing class, you cannot use
object.__init_subclass__
with attrs classes, because it runs too early. As a replacement, you can define__attrs_init_subclass__
on your class. It will be called by attrs classes that subclass it after they’re created. See also attrs and __init_subclass__.- Parameters:
slots (bool) – Create a slotted class that’s more memory-efficient. Slotted classes are generally superior to the default dict classes, but have some gotchas you should know about, so we encourage you to read the glossary entry.
auto_detect (bool) –
Instead of setting the init, repr, eq, and hash arguments explicitly, assume they are set to True unless any of the involved methods for one of the arguments is implemented in the current class (meaning, it is not inherited from some base class).
So, for example by implementing
__eq__
on a class yourself, attrs will deduceeq=False
and will create neither__eq__
nor__ne__
(but Python classes come with a sensible__ne__
by default, so it should be enough to only implement__eq__
in most cases).Passing True or False` to init, repr, eq, cmp, or hash overrides whatever auto_detect would determine.
auto_exc (bool) –
If the class subclasses
BaseException
(which implicitly includes any subclass of any exception), the following happens to behave like a well-behaved Python exception class:the values for eq, order, and hash are ignored and the instances compare and hash by the instance’s ids [1] ,
all attributes that are either passed into
__init__
or have a default value are additionally available as a tuple in theargs
attribute,the value of str is ignored leaving
__str__
to base classes.
on_setattr (Callable | list[Callable] | None | Literal[attrs.setters.NO_OP]) –
A callable that is run whenever the user attempts to set an attribute (either by assignment like
i.x = 42
or by usingsetattr
likesetattr(i, "x", 42)
). It receives the same arguments as validators: the instance, the attribute that is being modified, and the new value.If no exception is raised, the attribute is set to the return value of the callable.
If a list of callables is passed, they’re automatically wrapped in an
attrs.setters.pipe
.If left None, the default behavior is to run converters and validators whenever an attribute is set.
init (bool) –
Create a
__init__
method that initializes the attrs attributes. Leading underscores are stripped for the argument name, unless an alias is set on the attribute.See also
Initialization shows advanced ways to customize the generated
__init__
method, including executing code before and after.repr (bool) – Create a
__repr__
method with a human readable representation of attrs attributes.str (bool) – Create a
__str__
method that is identical to__repr__
. This is usually not necessary except forException
s.eq (bool | None) –
If True or None (default), add
__eq__
and__ne__
methods that check two instances for equality.See also
Comparison describes how to customize the comparison behavior going as far comparing NumPy arrays.
order (bool | None) –
If True, add
__lt__
,__le__
,__gt__
, and__ge__
methods that behave like eq above and allow instances to be ordered.They compare the instances as if they were tuples of their attrs attributes if and only if the types of both classes are identical.
If
None
mirror value of eq.See also
cmp (bool | None) – Setting cmp is equivalent to setting eq and order to the same value. Must not be mixed with eq or order.
unsafe_hash (bool | None) –
If None (default), the
__hash__
method is generated according how eq and frozen are set.If both are True, attrs will generate a
__hash__
for you.If eq is True and frozen is False,
__hash__
will be set to None, marking it unhashable (which it is).If eq is False,
__hash__
will be left untouched meaning the__hash__
method of the base class will be used. If the base class isobject
, this means it will fall back to id-based hashing.
Although not recommended, you can decide for yourself and force attrs to create one (for example, if the class is immutable even though you didn’t freeze it programmatically) by passing True or not. Both of these cases are rather special and should be used carefully.
See also
Our documentation on Hashing,
Python’s documentation on
object.__hash__
,and the GitHub issue that led to the default behavior for more details.
hash (bool | None) – Deprecated alias for unsafe_hash. unsafe_hash takes precedence.
cache_hash (bool) – Ensure that the object’s hash code is computed only once and stored on the object. If this is set to True, hashing must be either explicitly or implicitly enabled for this class. If the hash code is cached, avoid any reassignments of 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.
frozen (bool) –
Make instances immutable after initialization. If someone attempts to modify a frozen instance,
attrs.exceptions.FrozenInstanceError
is raised.Note
This is achieved by installing a custom
__setattr__
method on your class, so you can’t implement your own.True immutability is impossible in Python.
This does have a minor a runtime performance impact when initializing new instances. In other words:
__init__
is slightly slower withfrozen=True
.If a class is frozen, you cannot modify
self
in__attrs_post_init__
or a self-written__init__
. You can circumvent that limitation by usingobject.__setattr__(self, "attribute_name", value)
.Subclasses of a frozen class are frozen too.
kw_only (bool) – Make all attributes keyword-only in the generated
__init__
(if init is False, this parameter is ignored).weakref_slot (bool) – Make instances weak-referenceable. This has no effect unless slots is True.
field_transformer (Callable | None) –
A function that is called with the original class object and all fields right before attrs finalizes the class. You can use this, for example, to automatically add converters or validators to fields based on their types.
match_args (bool) – If True (default), set
__match_args__
on the class to support PEP 634 (Structural Pattern Matching). It is a tuple of all non-keyword-only__init__
parameter names on Python 3.10 and later. Ignored on older Python versions.collect_by_mro (bool) –
If True, attrs collects attributes from base classes correctly according to the method resolution order. If False, attrs will mimic the (wrong) behavior of
dataclasses
and PEP 681.See also issue #428.
getstate_setstate (bool | None) –
Note
This is usually only interesting for slotted classes and you should probably just set auto_detect to True.
If True,
__getstate__
and__setstate__
are generated and attached to the class. This is necessary for slotted classes to be pickleable. If left None, it’s True by default for slotted classes and False for dict classes.If auto_detect is True, and getstate_setstate is left None, and either
__getstate__
or__setstate__
is detected directly on the class (meaning: not inherited), it is set to False (this is usually what you want).auto_attribs (bool | None) –
If True, look at type annotations to determine which attributes to use, like
dataclasses
. If False, it will only look for explicitfield()
class attributes, like classic attrs.If left None, it will guess:
If any attributes are annotated and no unannotated
attrs.field
s are found, it assumes auto_attribs=True.Otherwise it assumes auto_attribs=False and tries to collect
attrs.field
s.
If attrs decides to look at type annotations, all fields must be annotated. If attrs encounters a field that is set to a
field()
/attr.ib
but lacks a type annotation, anattrs.exceptions.UnannotatedAttributeError
is raised. Usefield_name: typing.Any = field(...)
if you don’t want to set a type.Warning
For features that use the attribute name to create decorators (for example, validators), you still must assign
field()
/attr.ib
to them. Otherwise Python will either not find the name or try to use the default value to call, for example,validator
on it.Attributes annotated as
typing.ClassVar
, and attributes that are neither annotated nor set to anfield()
are ignored.A dictionary of name to the (private) return value of
field()
mappings. This is useful to avoid the definition of your attributes within the class body because you can’t (for example, if you want to add__repr__
methods to Django models) or don’t want to.If these is not
None
, attrs will not search the class body for attributes and will not remove any attributes from it.The order is deduced from the order of the attributes inside these.
Arguably, this is a rather obscure feature.
Added in version 20.1.0.
Changed in version 21.3.0: Converters are also run
on_setattr
.Added in version 22.2.0: unsafe_hash as an alias for hash (for PEP 681 compliance).
Changed in version 24.1.0: Instances are not compared as tuples of attributes anymore, but using a big
and
condition. This is faster and has more correct behavior for uncomparable values likemath.nan
.Added in version 24.1.0: If a class has an inherited classmethod called
__attrs_init_subclass__
, it is executed after the class is created.Deprecated since version 24.1.0: hash is deprecated in favor of unsafe_hash.
Note
The main differences to the classic
attr.s
are:Automatically detect whether or not auto_attribs should be
True
(c.f. auto_attribs parameter).Converters and validators run when attributes are set by default – if frozen is
False
.slots=True
Usually, this has only upsides and few visible effects in everyday programming. But it can lead to some surprising behaviors, so please make sure to read slotted classes.
auto_exc=True
auto_detect=True
order=False
Some options that were only relevant on Python 2 or were kept around for backwards-compatibility have been removed.
- attrs.mutable(same_as_define)¶
Same as
attrs.define
.Added in version 20.1.0.
- attrs.frozen(same_as_define)¶
Behaves the same as
attrs.define
but sets frozen=True and on_setattr=None.Added in version 20.1.0.
- attrs.field(*, default=NOTHING, validator=None, repr=True, hash=None, init=True, metadata=None, type=None, converter=None, factory=None, kw_only=False, eq=None, order=None, on_setattr=None, alias=None)¶
Create a new field / attribute on a class.
Warning
Does nothing unless the class is also decorated with
attrs.define
(or similar)!- Parameters:
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 usinginit=False
.If the value is an instance of
attrs.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
attrs.NOTHING
), a value must be supplied when instantiating; otherwise aTypeError
will be raised.See also
factory (Callable) – Syntactic sugar for
default=attr.Factory(factory)
.validator (Callable | list[Callable]) –
Callable that is called by attrs-generated
__init__
methods after the instance has been initialized. They receive the initialized instance, theAttribute()
, and the passed value.The return value is not inspected so the validator has to throw an exception itself.
If a
list
is passed, its items are treated as validators and must all pass.Validators can be globally disabled and re-enabled using
attrs.validators.get_disabled
/attrs.validators.set_disabled
.The validator can also be set using decorator notation as shown below.
See also
repr (bool | Callable) – Include this attribute in the generated
__repr__
method. If True, include the attribute; if False, omit it. By default, the built-inrepr()
function is used. To override how the attribute value is formatted, pass acallable
that takes a single value and returns a string. Note that the resulting string is used as-is, which means it will be used directly instead of callingrepr()
(the default).If True (default), include this attribute in the generated
__eq__
and__ne__
methods that check two instances for equality. To override how the attribute value is compared, pass a callable that takes a single value and returns the value to be compared.See also
If True (default), include this attributes in the generated
__lt__
,__le__
,__gt__
and__ge__
methods. To override how the attribute value is ordered, pass a callable that takes a single value and returns the value to be ordered.See also
Setting cmp is equivalent to setting eq and order to the same value. Must not be mixed with eq or order.
See also
hash (bool | None) –
Include this attribute in the generated
__hash__
method. If None (default), mirror eq’s value. This is the correct behavior according the Python spec. Setting this value to anything else than None is discouraged.See also
init (bool) –
Include this attribute in the generated
__init__
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.
See also
converter (Callable | Converter) –
A callable that is called by attrs-generated
__init__
methods to convert attribute’s value to the desired format.If a vanilla callable is passed, it is given the passed-in value as the only positional argument. It is possible to receive additional arguments by wrapping the callable in a
Converter
.Either way, 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.
See also
metadata (dict | None) –
An arbitrary mapping, to be used by third-party code.
See also
type (type) –
The type of the attribute. Nowadays, the preferred method to specify the type is using a variable annotation (see PEP 526). This argument is provided for backwards-compatibility and for usage with
make_class
. Regardless of the approach used, the type will be stored onAttribute.type
.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 static type checking.
kw_only (bool) – Make this attribute keyword-only in the generated
__init__
(ifinit
is False, this parameter is ignored).on_setattr (Callable | list[Callable] | None | Literal[attrs.setters.NO_OP]) – Allows to overwrite the on_setattr setting from
attr.s
. If left None, the on_setattr value fromattr.s
is used. Set toattrs.setters.NO_OP
to run nosetattr
hooks for this attribute – regardless of the setting indefine()
.alias (str | None) – Override this attribute’s parameter name in the generated
__init__
method. If left None, default toname
stripped of leading underscores. See Private Attributes and Aliases.
Added in version 20.1.0.
Changed in version 21.1.0: eq, order, and cmp also accept a custom callable
Added in version 22.2.0: alias
Added in version 23.1.0: The type parameter has been re-added; mostly for
attrs.make_class
. Please note that type checkers ignore this metadata.See also
- class attrs.Attribute(name, default, validator, repr, cmp, hash, init, inherited, metadata=None, type=None, converter=None, kw_only=False, eq=None, eq_key=None, order=None, order_key=None, on_setattr=None, alias=None)¶
Read-only representation of an attribute.
Warning
You should never instantiate this class yourself.
The class has all arguments of
attr.ib
(except forfactory
which is only syntactic sugar fordefault=Factory(...)
plus the following:name
(str
): The name of the attribute.alias
(str
): The __init__ parameter name of the attribute, after any explicit overrides and default private-attribute-name handling.inherited
(bool
): Whether or not that attribute has been inherited from a base class.eq_key
andorder_key
(typing.Callable
orNone
): The callables that are used for comparing and ordering objects by this attribute, respectively. These are set by passing a callable toattr.ib
’seq
,order
, orcmp
arguments. See also comparison customization.
Instances of this class are frequently used for introspection purposes like:
fields
returns a tuple of them.Validators get them passed as the first argument.
The field transformer hook receives a list of them.
The
alias
property exposes the __init__ parameter name of the field, with any overrides and default private-attribute handling applied.
Added in version 20.1.0: inherited
Added in version 20.1.0: on_setattr
Changed in version 20.2.0: inherited is not taken into account for equality checks and hashing anymore.
Added in version 21.1.0: eq_key and order_key
Added in version 22.2.0: alias
For the full version history of the fields, see
attr.ib
.For example:
>>> import attrs >>> from attrs import define, field >>> @define ... class C: ... x = field() >>> attrs.fields(C).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')
- evolve(**changes)¶
Copy self and apply changes.
This works similarly to
attrs.evolve
but that function does not work with {class}`Attribute`.It is mainly meant to be used for Automatic Field Transformation and Modification.
Added in version 20.3.0.
- attrs.make_class(name, attrs, bases=(<class 'object'>, ), class_body=None, **attributes_arguments)¶
A quick way to create a new class called name with attrs.
- Parameters:
name (str) – The name for the new class.
A list of names or a dictionary of mappings of names to
attr.ib
s /attrs.field
s.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.
bases (tuple[type, ...]) – Classes that the new class will subclass.
class_body (dict) – An optional dictionary of class attributes for the new class.
attributes_arguments – Passed unmodified to
attr.s
.
- Returns:
A new class with attrs.
- Return type:
Added in version 17.1.0: bases
Changed in version 18.1.0: If attrs is ordered, the order is retained.
Changed in version 23.2.0: class_body
This is handy if you want to programmatically create classes.
For example:
>>> C1 = attrs.make_class("C1", ["x", "y"]) >>> C1(1, 2) C1(x=1, y=2) >>> C2 = attrs.make_class("C2", { ... "x": field(default=42), ... "y": field(factory=list) ... }) >>> C2() C2(x=42, y=[])
- class attrs.Factory(factory, takes_self=False)¶
Stores a factory callable.
If passed as the default value to
attrs.field
, the factory is used to generate a new value.- Parameters:
Added in version 17.1.0: takes_self
For example:
>>> @define ... class C: ... x = field(default=attrs.Factory(list)) ... y = field(default=attrs.Factory( ... 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})
Exceptions¶
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:
>>> import attrs, attr
>>> try:
... raise attrs.exceptions.FrozenError()
... except attr.exceptions.FrozenError:
... print("this works!")
this works!
- exception attrs.exceptions.PythonTooOldError¶
It was attempted to use an attrs feature that requires a newer Python version.
Added in version 18.2.0.
- exception attrs.exceptions.FrozenError¶
A frozen/immutable instance or attribute have been attempted to be modified.
It mirrors the behavior of
namedtuples
by using the same error message and subclassingAttributeError
.Added in version 20.1.0.
- exception attrs.exceptions.FrozenInstanceError¶
A frozen instance has been attempted to be modified.
Added in version 16.1.0.
- exception attrs.exceptions.FrozenAttributeError¶
A frozen attribute has been attempted to be modified.
Added in version 20.1.0.
- exception attrs.exceptions.AttrsAttributeNotFoundError¶
An attrs function couldn’t find an attribute that the user asked for.
Added in version 16.2.0.
- exception attrs.exceptions.NotAnAttrsClassError¶
A non-attrs class has been passed into an attrs function.
Added in version 16.2.0.
- exception attrs.exceptions.DefaultAlreadySetError¶
A default has been set when defining the field and is attempted to be reset using the decorator.
Added in version 17.1.0.
- exception attrs.exceptions.NotCallableError(msg, value)¶
A field requiring a callable has been set with a value that is not callable.
Added in version 19.2.0.
- exception attrs.exceptions.UnannotatedAttributeError¶
A class with
auto_attribs=True
has a field without a type annotation.Added in version 17.3.0.
For example:
@attr.s(auto_attribs=True) class C: x: int y = attr.ib() # <- ERROR!
Helpers¶
attrs comes with a bunch of helper methods that make working with it easier:
- attrs.cmp_using(eq=None, lt=None, le=None, gt=None, ge=None, require_same_type=True, class_name='Comparable')¶
Create a class that can be passed into
attrs.field
’seq
,order
, andcmp
arguments to customize field comparison.The resulting class will have a full set of ordering methods if at least one of
{lt, le, gt, ge}
andeq
are provided.- Parameters:
eq (Callable | None) – Callable used to evaluate equality of two objects.
lt (Callable | None) – Callable used to evaluate whether one object is less than another object.
le (Callable | None) – Callable used to evaluate whether one object is less than or equal to another object.
gt (Callable | None) – Callable used to evaluate whether one object is greater than another object.
ge (Callable | None) – Callable used to evaluate whether one object is greater than or equal to another object.
require_same_type (bool) – When
True
, equality and ordering methods will returnNotImplemented
if objects are not of the same type.class_name (str | None) – Name of class. Defaults to “Comparable”.
See Comparison for more details.
Added in version 21.1.0.
- attrs.fields(cls)¶
Return the tuple of attrs attributes for a class.
The tuple also allows accessing the fields by their names (see below for examples).
- Parameters:
cls (type) – Class to introspect.
- Raises:
TypeError – If cls is not a class.
attrs.exceptions.NotAnAttrsClassError – If cls is not an attrs class.
- Returns:
tuple (with name accessors) of
attrs.Attribute
Changed in version 16.2.0: Returned tuple allows accessing the fields by name.
Changed in version 23.1.0: Add support for generic classes.
For example:
>>> @define ... class C: ... x = field() ... y = field() >>> attrs.fields(C) (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')) >>> attrs.fields(C)[1] 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') >>> attrs.fields(C).y is attrs.fields(C)[1] True
- attrs.fields_dict(cls)¶
Return an ordered dictionary of attrs attributes for a class, whose keys are the attribute names.
- Parameters:
cls (type) – Class to introspect.
- Raises:
TypeError – If cls is not a class.
attrs.exceptions.NotAnAttrsClassError – If cls is not an attrs class.
- Returns:
Dict of attribute name to definition
- Return type:
Added in version 18.1.0.
For example:
>>> @attr.s ... class C: ... x = attr.ib() ... y = attr.ib() >>> attrs.fields_dict(C) {'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')} >>> attr.fields_dict(C)['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') >>> attrs.fields_dict(C)['y'] is attrs.fields(C).y True
- attrs.has(cls)¶
Check whether cls is a class with attrs attributes.
- Parameters:
cls (type) – Class to introspect.
- Raises:
TypeError – If cls is not a class.
- Return type:
For example:
>>> @attr.s ... class C: ... pass >>> attr.has(C) True >>> attr.has(object) False
- attrs.resolve_types(cls, globalns=None, localns=None, attribs=None, include_extras=True)¶
Resolve any strings and forward annotations in type annotations.
This is only required if you need concrete types in
Attribute
’s type field. In other words, you don’t need to resolve your types if you only use them for static type checking.With no arguments, names will be looked up in the module in which the class was created. If this is not what you want, for example, if the name only exists inside a method, you may pass globalns or localns to specify other dictionaries in which to look up these names. See the docs of
typing.get_type_hints
for more details.- Parameters:
cls (type) – Class to resolve.
globalns (dict | None) – Dictionary containing global variables.
localns (dict | None) – Dictionary containing local variables.
attribs (list | None) – List of attribs for the given class. This is necessary when calling from inside a
field_transformer
since cls is not an attrs class yet.include_extras (bool) – Resolve more accurately, if possible. Pass
include_extras
totyping.get_hints
, if supported by the typing module. On supported Python versions (3.9+), this resolves the types more accurately.
- Raises:
TypeError – If cls is not a class.
attrs.exceptions.NotAnAttrsClassError – If cls is not an attrs class and you didn’t pass any attribs.
NameError – If types cannot be resolved because of missing variables.
- Returns:
cls so you can use this function also as a class decorator. Please note that you have to apply it after
attrs.define
. That means the decorator has to come in the line beforeattrs.define
.
Added in version 20.1.0.
Added in version 21.1.0: attribs
Added in version 23.1.0: include_extras
For example:
>>> import typing >>> @define ... class A: ... a: typing.List['A'] ... b: 'B' ... >>> @define ... class B: ... a: A ... >>> attrs.fields(A).a.type typing.List[ForwardRef('A')] >>> attrs.fields(A).b.type 'B' >>> attrs.resolve_types(A, globals(), locals()) <class 'A'> >>> attrs.fields(A).a.type typing.List[A] >>> attrs.fields(A).b.type <class 'B'>
- attrs.asdict(inst, *, recurse=True, filter=None, value_serializer=None)¶
Same as
attr.asdict
, except that collections types are always retained and dict is always used as dict_factory.Added in version 21.3.0.
For example:
>>> @define ... class C: ... x: int ... y: int >>> attrs.asdict(C(1, C(2, 3))) {'x': 1, 'y': {'x': 2, 'y': 3}}
- attrs.astuple(inst, *, recurse=True, filter=None)¶
Same as
attr.astuple
, except that collections types are always retained andtuple
is always used as the tuple_factory.Added in version 21.3.0.
For example:
>>> @define ... class C: ... x = field() ... y = field() >>> attrs.astuple(C(1,2)) (1, 2)
attrs includes helpers for filtering the attributes in attrs.asdict
and attrs.astuple
:
- attrs.filters.include(*what)¶
Create a filter that only allows what.
- Parameters:
what (list[type, str, attrs.Attribute]) – What to include. Can be a type, a name, or an attribute.
- Returns:
A callable that can be passed to
attrs.asdict
’s andattrs.astuple
’s filter argument.- Return type:
Callable
Changed in version 23.1.0: Accept strings with field names.
- attrs.filters.exclude(*what)¶
Create a filter that does not allow what.
- Parameters:
what (list[type, str, attrs.Attribute]) – What to exclude. Can be a type, a name, or an attribute.
- Returns:
A callable that can be passed to
attrs.asdict
’s andattrs.astuple
’s filter argument.- Return type:
Callable
Changed in version 23.3.0: Accept field name string as input argument
See attrs.asdict()
for examples.
All objects from attrs.filters
are also available from attr.filters
(it’s the same module in a different namespace).
- attrs.evolve(*args, **changes)¶
Create a new instance, based on the first positional argument with changes applied.
- Parameters:
inst – Instance of a class with attrs attributes. inst must be passed as a positional argument.
changes – Keyword changes in the new copy.
- Returns:
A copy of inst with changes incorporated.
- Raises:
TypeError – If attr_name couldn’t be found in the class
__init__
.attrs.exceptions.NotAnAttrsClassError – If cls is not an attrs class.
Added in version 17.1.0.
Deprecated since version 23.1.0: It is now deprecated to pass the instance using the keyword argument inst. It will raise a warning until at least April 2024, after which it will become an error. Always pass the instance as a positional argument.
Changed in version 24.1.0: inst can’t be passed as a keyword argument anymore.
For example:
>>> @define ... class C: ... x: int ... y: int >>> i1 = C(1, 2) >>> i1 C(x=1, y=2) >>> i2 = attrs.evolve(i1, y=3) >>> i2 C(x=1, y=3) >>> i1 == i2 False
evolve
creates a new instance using__init__
. This fact has several implications:private attributes should be specified without the leading underscore, just like in
__init__
.attributes with
init=False
can’t be set withevolve
.the usual
__init__
validators will validate the new values.
- attrs.validate(inst)¶
Validate all attributes on inst that have a validator.
Leaves all exceptions through.
- Parameters:
inst – Instance of a class with attrs attributes.
For example:
>>> @define(on_setattr=attrs.setters.NO_OP) ... class C: ... x = field(validator=attrs.validators.instance_of(int)) >>> i = C(1) >>> i.x = "1" >>> attrs.validate(i) Traceback (most recent call last): ... TypeError: ("'x' must be <class 'int'> (got '1' that is a <class 'str'>).", ...)
Validators¶
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).
- attrs.validators.lt(val)¶
A validator that raises
ValueError
if the initializer is called with a number larger or equal to val.The validator uses
operator.lt
to compare the values.- Parameters:
val – Exclusive upper bound for values.
Added in version 21.3.0.
For example:
>>> @define ... class C: ... x = field(validator=attrs.validators.lt(42)) >>> C(41) C(x=41) >>> C(42) Traceback (most recent call last): ... ValueError: ("'x' must be < 42: 42")
- attrs.validators.le(val)¶
A validator that raises
ValueError
if the initializer is called with a number greater than val.The validator uses
operator.le
to compare the values.- Parameters:
val – Inclusive upper bound for values.
Added in version 21.3.0.
For example:
>>> @define ... class C: ... x = field(validator=attrs.validators.le(42)) >>> C(42) C(x=42) >>> C(43) Traceback (most recent call last): ... ValueError: ("'x' must be <= 42: 43")
- attrs.validators.ge(val)¶
A validator that raises
ValueError
if the initializer is called with a number smaller than val.The validator uses
operator.ge
to compare the values.- Parameters:
val – Inclusive lower bound for values
Added in version 21.3.0.
For example:
>>> @define ... class C: ... x = attrs.field(validator=attrs.validators.ge(42)) >>> C(42) C(x=42) >>> C(41) Traceback (most recent call last): ... ValueError: ("'x' must be => 42: 41")
- attrs.validators.gt(val)¶
A validator that raises
ValueError
if the initializer is called with a number smaller or equal to val.The validator uses
operator.ge
to compare the values.- Parameters:
val – Exclusive lower bound for values
Added in version 21.3.0.
For example:
>>> @define ... class C: ... x = field(validator=attrs.validators.gt(42)) >>> C(43) C(x=43) >>> C(42) Traceback (most recent call last): ... ValueError: ("'x' must be > 42: 42")
- attrs.validators.max_len(length)¶
A validator that raises
ValueError
if the initializer is called with a string or iterable that is longer than length.- Parameters:
length (int) – Maximum length of the string or iterable
Added in version 21.3.0.
For example:
>>> @define ... class C: ... x = field(validator=attrs.validators.max_len(4)) >>> C("spam") C(x='spam') >>> C("bacon") Traceback (most recent call last): ... ValueError: ("Length of 'x' must be <= 4: 5")
- attrs.validators.min_len(length)¶
A validator that raises
ValueError
if the initializer is called with a string or iterable that is shorter than length.- Parameters:
length (int) – Minimum length of the string or iterable
Added in version 22.1.0.
For example:
>>> @define ... class C: ... x = field(validator=attrs.validators.min_len(1)) >>> C("bacon") C(x='bacon') >>> C("") Traceback (most recent call last): ... ValueError: ("Length of 'x' must be => 1: 0")
- attrs.validators.instance_of(type)¶
A validator that raises a
TypeError
if the initializer is called with a wrong type for this particular attribute (checks are performed usingisinstance
therefore it’s also valid to pass a tuple of types).- Parameters:
- Raises:
TypeError – With a human readable error message, the attribute (of type
attrs.Attribute
), the expected type, and the value it got.
For example:
>>> @define ... class C: ... x = field(validator=attrs.validators.instance_of(int)) >>> C(42) C(x=42) >>> C("42") Traceback (most recent call last): ... 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') >>> C(None) Traceback (most recent call last): ... 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)
- attrs.validators.in_(options)¶
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
, so options has to support that operation.To keep the validator hashable, dicts, lists, and sets are transparently transformed into a
tuple
.- Parameters:
options – Allowed options.
- Raises:
ValueError – With a human readable error message, the attribute (of type
attrs.Attribute
), the expected options, and the value it got.
Added in version 17.1.0.
Changed in version 22.1.0: The ValueError was incomplete until now and only contained the human readable error message. Now it contains all the information that has been promised since 17.1.0.
Changed in version 24.1.0: options that are a list, dict, or a set are now transformed into a tuple to keep the validator hashable.
For example:
>>> import enum >>> class State(enum.Enum): ... ON = "on" ... OFF = "off" >>> @define ... class C: ... state = field(validator=attrs.validators.in_(State)) ... val = field(validator=attrs.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'), 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') >>> 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)
- attrs.validators.and_(*validators)¶
A validator that composes multiple validators into one.
When called on a value, it runs all wrapped validators.
Added in version 17.1.0.
For convenience, it’s also possible to pass a list to
attrs.field
’s validator argument.Thus the following two statements are equivalent:
x = field(validator=attrs.validators.and_(v1, v2, v3)) x = field(validator=[v1, v2, v3])
- attrs.validators.or_(*validators)¶
A validator that composes multiple validators into one.
When called on a value, it runs all wrapped validators until one of them is satisfied.
- Parameters:
validators (Iterable[Callable]) – Arbitrary number of validators.
- Raises:
ValueError – If no validator is satisfied. Raised with a human-readable error message listing all the wrapped validators and the value that failed all of them.
Added in version 24.1.0.
For example:
>>> @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'
- attrs.validators.not_(validator, *, msg=None, exc_types=(<class 'ValueError'>, <class 'TypeError'>))¶
A validator that wraps and logically ‘inverts’ the validator passed to it. It will raise a
ValueError
if the provided validator doesn’t raise aValueError
orTypeError
(by default), and will suppress the exception if the provided validator does.Intended to be used with existing validators to compose logic without needing to create inverted variants, for example,
not_(in_(...))
.- Parameters:
- Raises:
ValueError – With a human readable error message, the attribute (of type
attrs.Attribute
), the validator that failed to raise an exception, the value it got, and the expected exception types.
Added in version 22.2.0.
For example:
>>> reserved_names = {"id", "time", "source"} >>> @define ... class Measurement: ... tags = field( ... 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'})
- attrs.validators.optional(validator)¶
A validator that makes an attribute optional. An optional attribute is one which can be set to
None
in addition to satisfying the requirements of the sub-validator.- Parameters:
validator – (typing.Callable | tuple[typing.Callable] | list[typing.Callable]): A validator (or validators) that is used for non-
None
values.
Added in version 15.1.0.
Changed in version 17.1.0: validator can be a list of validators.
Changed in version 23.1.0: validator can also be a tuple of validators.
For example:
>>> @define ... class C: ... x = field( ... validator=attrs.validators.optional( ... attrs.validators.instance_of(int) ... )) >>> C(42) C(x=42) >>> C("42") Traceback (most recent call last): ... 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') >>> C(None) C(x=None)
- attrs.validators.is_callable()¶
A validator that raises a
attrs.exceptions.NotCallableError
if the initializer is called with a value for this particular attribute that is not callable.Added in version 19.1.0.
- Raises:
attrs.exceptions.NotCallableError – With a human readable error message containing the attribute (
attrs.Attribute
) name, and the value it got.
For example:
>>> @define ... class C: ... x = field(validator=attrs.validators.is_callable()) >>> C(isinstance) C(x=<built-in function isinstance>) >>> C("not a callable") Traceback (most recent call last): ... attr.exceptions.NotCallableError: 'x' must be callable (got 'not a callable' that is a <class 'str'>).
- attrs.validators.matches_re(regex, flags=0, func=None)¶
A validator that raises
ValueError
if the initializer is called with a string that doesn’t match regex.- Parameters:
regex (str, re.Pattern) – A regex string or precompiled pattern to match against
flags (int) – Flags that will be passed to the underlying re function (default 0)
func (Callable) – Which underlying
re
function to call. Valid options arere.fullmatch
,re.search
, andre.match
; the defaultNone
meansre.fullmatch
. For performance reasons, the pattern is always precompiled usingre.compile
.
Added in version 19.2.0.
Changed in version 21.3.0: regex can be a pre-compiled pattern.
For example:
>>> @define ... class User: ... email = field(validator=attrs.validators.matches_re( ... r"(^[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')
- attrs.validators.deep_iterable(member_validator, iterable_validator=None)¶
A validator that performs deep validation of an iterable.
- Parameters:
member_validator – Validator to apply to iterable members.
iterable_validator – Validator to apply to iterable itself (optional).
- Raises
TypeError: if any sub-validators fail
Added in version 19.1.0.
For example:
>>> @define ... class C: ... x = field(validator=attrs.validators.deep_iterable( ... member_validator=attrs.validators.instance_of(int), ... iterable_validator=attrs.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')
- attrs.validators.deep_mapping(key_validator, value_validator, mapping_validator=None)¶
A validator that performs deep validation of a dictionary.
- Parameters:
key_validator – Validator to apply to dictionary keys.
value_validator – Validator to apply to dictionary values.
mapping_validator – Validator to apply to top-level mapping attribute (optional).
Added in version 19.1.0.
- Raises:
TypeError – if any sub-validators fail
For example:
>>> @define ... class C: ... 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) ... )) >>> 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)
Validators can be both globally and locally disabled:
- attrs.validators.set_disabled(disabled)¶
Globally disable or enable running validators.
By default, they are run.
Warning
This function is not thread-safe!
Added in version 21.3.0.
- attrs.validators.get_disabled()¶
Return a bool indicating whether validators are currently disabled or not.
Added in version 21.3.0.
- attrs.validators.disabled()¶
Context manager that disables running validators within its context.
Warning
This context manager is not thread-safe!
Added in version 21.3.0.
Converters¶
- class attrs.Converter(converter, *, takes_self=False, takes_field=False)¶
Stores a converter callable.
Allows for the wrapped converter to take additional arguments. The arguments are passed in the order they are documented.
- Parameters:
converter (Callable) – A callable that converts the passed value.
takes_self (bool) – Pass the partially initialized instance that is being initialized as a positional argument. (default:
False
)takes_field (bool) – Pass the field definition (an
Attribute
) into the converter as a positional argument. (default:False
)
Added in version 24.1.0.
For example:
>>> 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)
All objects from attrs.converters
are also available from attr.converters
(it’s the same module in a different namespace).
- attrs.converters.pipe(*converters)¶
A converter that composes multiple converters into one.
When called on a value, it runs all wrapped converters, returning the last value.
Type annotations will be inferred from the wrapped converters’, if they have any.
- converters (~collections.abc.Iterable[typing.Callable]):
Arbitrary number of converters.
Added in version 20.1.0.
For convenience, it’s also possible to pass a list to
attrs.field
/attr.ib
’s converter arguments.Thus the following two statements are equivalent:
x = attrs.field(converter=attrs.converter.pipe(c1, c2, c3)) x = attrs.field(converter=[c1, c2, c3])
- attrs.converters.optional(converter)¶
A converter that allows an attribute to be optional. An optional attribute is one which can be set to
None
.Type annotations will be inferred from the wrapped converter’s, if it has any.
Added in version 17.1.0.
For example:
>>> @define ... class C: ... x = field(converter=attrs.converters.optional(int)) >>> C(None) C(x=None) >>> C(42) C(x=42)
- attrs.converters.default_if_none(default=NOTHING, factory=None)¶
A converter that allows to replace
None
values by default or the result of factory.- Parameters:
default – Value to be used if
None
is passed. Passing an instance ofattrs.Factory
is supported, however thetakes_self
option is not.factory (Callable) – A callable that takes no parameters whose result is used if
None
is passed.
- Raises:
TypeError – If neither default or factory is passed.
TypeError – If both default and factory are passed.
ValueError – If an instance of
attrs.Factory
is passed withtakes_self=True
.
Added in version 18.2.0.
For example:
>>> @define ... class C: ... x = field( ... converter=attrs.converters.default_if_none("") ... ) >>> C(None) C(x='')
- attrs.converters.to_bool(val)¶
Convert “boolean” strings (for example, from environment variables) to real booleans.
Values mapping to
True
:True
"true"
/"t"
"yes"
/"y"
"on"
"1"
1
Values mapping to
False
:False
"false"
/"f"
"no"
/"n"
"off"
"0"
0
- Raises:
ValueError – For any other value.
Added in version 21.3.0.
For example:
>>> @define ... class C: ... x = field( ... converter=attrs.converters.to_bool ... ) >>> C("yes") C(x=True) >>> C(0) C(x=False) >>> C("norway") Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: Cannot convert value to bool: norway
Setters¶
These are helpers that you can use together with attrs.define
’s and attrs.field
’s on_setattr
arguments.
All setters in attrs.setters
are also available from attr.setters
(it’s the same module in a different namespace).
- attrs.setters.frozen(_, __, ___)¶
Prevent an attribute to be modified.
Added in version 20.1.0.
- attrs.setters.validate(instance, attrib, new_value)¶
Run attrib’s validator on new_value if it has one.
Added in version 20.1.0.
- attrs.setters.convert(instance, attrib, new_value)¶
Run attrib’s converter – if it has one – on new_value and return the result.
Added in version 20.1.0.
- attrs.setters.pipe(*setters)¶
Run all setters and return the return value of the last one.
Added in version 20.1.0.
- attrs.setters.NO_OP¶
Sentinel for disabling class-wide on_setattr hooks for certain attributes.
Does not work in
attrs.setters.pipe
or within lists.Added in version 20.1.0.
For example, only
x
is frozen here:>>> @define(on_setattr=attr.setters.frozen) ... class C: ... x = field() ... y = field(on_setattr=attr.setters.NO_OP) >>> c = C(1, 2) >>> c.y = 3 >>> c.y 3 >>> c.x = 4 Traceback (most recent call last): ... attrs.exceptions.FrozenAttributeError: ()
Tip
Use
attrs.define
’s frozen argument (orattrs.frozen
) to freeze whole classes; it is more efficient.