Install & Compatibility
Where this runs
tested against v26.1.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.925 runs
installs and imports cleanly · install 0.0s · import 0.079s · 18.3MB
glibcpy 3.10–3.925 runs
installs and imports cleanly · install 1.6s · import 0.071s · 19MB
16MB installed
● package 16MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
define
✓ from attrs import define
field
✓ from attrs import field
s
✓ import attr; attr.s
✗ from attr import s
The `s` decorator is part of the classic `attr` namespace, imported as `attr`. Modern usage prefers `from attrs import define`.
ib
✓ import attr; attr.ib
✗ from attr import ib
The `ib` function is part of the classic `attr` namespace, imported as `attr`. Modern usage prefers `from attrs import field`.
This quickstart demonstrates defining a simple `User` class using the modern `attrs.define` decorator and `attrs.field` for attributes. It showcases automatic `__init__`, `__repr__`, and `__eq__` generation.
from attrs import define, field
@define
class User:
id: int = field()
name: str = field()
email: str = field(default='no-email@example.com')
# Create instances
user1 = User(id=1, name='Alice')
user2 = User(id=2, name='Bob', email='bob@example.com')
print(user1)
print(user2)
print(user1 == User(id=1, name='Alice')) # Automatically generated equality
Debug
Known issues
breakingAs of `attrs` version 21.3.0, when using the modern `@define` decorator, converters are now run by default when an attribute is set on an instance, in addition to validators. This changes the default behavior of `on_setattr` to `[attrs.setters.convert, attrs.setters.validate]`.fixIf this change in behavior is undesirable, explicitly set `on_setattr=None` or define a custom `on_setattr` callable for your attributes or class.
affects: >=21.3.0
gotchaattrs provides two main API namespaces: the classic `attr` (e.g., `attr.s`, `attr.ib`) and the newer `attrs` (e.g., `attrs.define`, `attrs.field`). While the `attr` namespace is supported indefinitely, the `attrs` namespace offers more modern APIs and better defaults, especially since version 20.1.0 and the introduction of `import attrs` in 21.3.0. New development should favor the `attrs` namespace.fixFor new projects or modernizing existing code, use `from attrs import define, field` instead of `import attr` and `attr.s`/`attr.ib`.
affects: All versions, especially when migrating or starting new projects.
gotchaThe internal structure of the `attrs.Attribute` class is subject to change in future versions and is not considered part of the stable public API for extensions. While it can be read, relying on its internal structure for building complex extensions is discouraged.fixTreat `attrs.Attribute` as a read-only data structure. If building extensions, be prepared for potential adjustments to your code if it depends on the precise internal layout of `attrs.Attribute`.
affects: All versions
deprecatedThe `attr.s(collect_by_mro=False)` argument, which controls how attributes are collected from base classes in inheritance hierarchies, will have its default value changed to `True` in a future release. This could alter behavior for certain multiple-inheritance scenarios.fixIf your code relies on the current `collect_by_mro=False` behavior (where attributes are not collected by MRO by default), explicitly set `collect_by_mro=False` to maintain current behavior. Consider testing with `collect_by_mro=True` to understand potential future impacts.
affects: All versions prior to the change.
Upgrade
Version history
26.1.0latest on PyPI · released Mar 19, 2026
Audit
Dependencies
No dependency data recorded yet.