Versions follow [CalVer](https://calver.org) with a strict backwards-compatibility policy.
The **first number** of the version is the year.
The **second number** is incremented with each release, starting at 1 for each year.
The **third number** is when we need to start branches for older releases (only for emergencies).
Put simply, you shouldn't ever be afraid to upgrade `attrs` if you're only using its public APIs.
Whenever there is a need to break compatibility, it is announced here in the changelog, and raises a `DeprecationWarning` for a year (if possible) before it's finally really broken.
> **Warning**
> The structure of the `attrs.Attribute` class is exempt from this rule.
> It *will* change in the future, but since it should be considered read-only, that shouldn't matter.
>
> However if you intend to build extensions on top of `attrs` you have to anticipate that.
Changes for the upcoming release can be found in the ["changelog.d" directory](https://github.com/python-attrs/attrs/tree/main/changelog.d) in our repository.
-`attrs.field()` now supports an *alias* option for explicit `__init__` argument names.
Get `__init__` signatures matching any taste, peculiar or plain!
The [PEP 681 compatible](https://peps.python.org/pep-0681/#field-specifier-parameters) *alias* option can be use to override private attribute name mangling, or add other arbitrary field argument name overrides.
-`attrs.NOTHING` is now an enum value, making it possible to use with e.g. [`typing.Literal`](https://docs.python.org/3/library/typing.html#typing.Literal).
- On Python 3.10 and later, call [`abc.update_abstractmethods()`](https://docs.python.org/3/library/abc.html#abc.update_abstractmethods) on dict classes after creation.
- Added `attrs.validators.not_(wrapped_validator)` to logically invert *wrapped_validator* by accepting only values where *wrapped_validator* rejects the value with a `ValueError` or `TypeError` (by default, exception types configurable).
-`attrs.validators.deep_iterable()`'s *member_validator* argument now also accepts a list of validators and wraps them in an `attrs.validators.and_()`.
- When using `@define`, converters are now run by default when setting an attribute on an instance -- additionally to validators.
I.e. the new default is `on_setattr=[attrs.setters.convert, attrs.setters.validate]`.
This is unfortunately a breaking change, but it was an oversight, impossible to raise a `DeprecationWarning` about, and it's better to fix it now while the APIs are very fresh with few users.
- If the class-level *on_setattr* is set to `attrs.setters.validate` (default in `@define` and `@mutable`) but no field defines a validator, pretend that it's not set.
- Added **provisional** support for static typing in `pyright` via the [dataclass_transforms specification](https://github.com/microsoft/pyright/blob/main/specs/dataclass_transforms.md).
Both the `pyright` specification and `attrs` implementation may change in future versions of both projects.
Your constructive feedback is welcome in both [attrs#795](https://github.com/python-attrs/attrs/issues/795) and [pyright#1782](https://github.com/microsoft/pyright/discussions/1782).
-`attr.define()`, `attr.frozen()`, `attr.mutable()`, and `attr.field()` remain **provisional**.
This release does **not** change anything about them and they are already used widely in production though.
If you wish to use them together with mypy, you can simply drop [this plugin](https://gist.github.com/hynek/1e3844d0c99e479e716169034b5fa963#file-attrs_ng_plugin-py) into your project.
Feel free to provide feedback to them in the linked issue #668.
We will release the `attrs` namespace once we have the feeling that the APIs have properly settled.
-`attr.define()`, `attr.frozen()`, `attr.mutable()`, and `attr.field()` remain **provisional**.
This release fixes a bunch of bugs and ergonomics but they remain mostly unchanged.
If you wish to use them together with mypy, you can simply drop [this plugin](https://gist.github.com/hynek/1e3844d0c99e479e716169034b5fa963#file-attrs_ng_plugin-py) into your project.
Feel free to provide feedback to them in the linked issue #668.
We will release the `attrs` namespace once we have the feeling that the APIs have properly settled.
- In 20.1.0 we introduced the `inherited` attribute on the `attr.Attribute` class to differentiate attributes that have been inherited and those that have been defined directly on the class.
It has shown to be problematic to involve that attribute when comparing instances of `attr.Attribute` though, because when sub-classing, attributes from base classes are suddenly not equal to themselves in a super class.
Therefore the `inherited` attribute will now be ignored when hashing and comparing instances of `attr.Attribute`.
-`zope.interface` is now a "soft dependency" when running the test suite; if `zope.interface` is not installed when running the test suite, the interface-related tests will be automatically skipped.
It has been unsupported by the Python core team for a while now, its PyPI downloads are negligible, and our CI provider removed it as a supported option.
It's very unlikely that `attrs` will break under 3.4 anytime soon, which is why we do *not* block its installation on Python 3.4.
But we don't test it anymore and will block it once someone reports breakage.
- Added `@attr.s(collect_by_mro=False)` argument that if set to `True` fixes the collection of attributes from base classes.
It's only necessary for certain cases of multiple-inheritance but is kept off for now for backward-compatibility reasons.
It will be turned on by default in the future.
As a side-effect, `attr.Attribute` now *always* has an `inherited` attribute indicating whether an attribute on a class was directly defined or inherited.
- It is now possible to prevent `attrs` from auto-generating the `__setstate__` and `__getstate__` methods that are required for pickling of slotted classes.
Either pass `@attr.s(getstate_setstate=False)` or pass `@attr.s(auto_detect=True)` and implement them yourself:
if `attrs` finds either of the two methods directly on the decorated class, it assumes implicitly `getstate_setstate=False` (and implements neither).
This option works with dict classes but should never be necessary.
-`attrs` can now automatically detect your own implementations and infer `init=False`, `repr=False`, `eq=False`, `order=False`, and `hash=False` if you set `@attr.s(auto_detect=True)`.
`attrs` will ignore inherited methods.
If the argument implies more than one method (e.g. `eq=True` creates both `__eq__` and `__ne__`), it's enough for *one* of them to exist and `attrs` will create *neither*.
- It is now possible to specify hooks that are called whenever an attribute is set **after** a class has been instantiated.
You can pass `on_setattr` both to `@attr.s()` to set the default for all attributes on a class, and to `@attr.ib()` to overwrite it for individual attributes.
`attrs` also comes with a new module `attr.setters` that brings helpers that run validators, converters, or allow to freeze a subset of attributes.
- The `cmp` argument to `attr.s()` and `attr.ib()` is now deprecated.
Please use `eq` to add equality methods (`__eq__` and `__ne__`) and `order` to add ordering methods (`__lt__`, `__le__`, `__gt__`, and `__ge__`) instead – just like with [dataclasses](https://docs.python.org/3/library/dataclasses.html).
Both are effectively `True` by default but it's enough to set `eq=False` to disable both at once.
Passing `eq=False, order=True` explicitly will raise a `ValueError` though.
Since this is arguably a deeper backward-compatibility break, it will have an extended deprecation period until 2021-06-01.
After that day, the `cmp` argument will be removed.
- Slotted classes now use a pure Python mechanism to rewrite the `__class__` cell when rebuilding the class, so `super()` works even on environments where `ctypes` is not installed.
-`attr.validators.is_callable()` validator now raises an exception `attr.exceptions.NotCallableError`, a subclass of `TypeError`, informing the received value.
- Keyword-only attributes (`kw_only=True`) and attributes that are excluded from the `attrs`'s `__init__` (`init=False`) now can appear before mandatory attributes.
-`attrs` now has first class support for defining exception classes.
If you define a class using `@attr.s(auto_exc=True)` and subclass an exception, the class will behave like a well-behaved exception class including an appropriate `__str__` method, and all attributes additionally available in an `args` attribute.
- Added *kw_only* arguments to `attr.ib` and `attr.s`, and a corresponding *kw_only* attribute to `attr.Attribute`.
This change makes it possible to have a generated `__init__` with keyword-only arguments on Python 3, relaxing the required ordering of default and non-default valued attributes.
- The order of attributes that are passed into `attr.make_class()` or the *these* argument of `@attr.s()` is now retained if the dictionary is ordered (i.e. `dict` on Python 3.6 and later, `collections.OrderedDict` otherwise).
Before, the order was always determined by the order in which the attributes have been defined which may not be desirable when creating classes programmatically.
- We have restructured the documentation a bit to account for `attrs`' growth in scope.
Instead of putting everything into the [examples](https://www.attrs.org/en/stable/examples.html) page, we have started to extract narrative chapters.
So far, we've added chapters on [initialization](https://www.attrs.org/en/stable/init.html) and [hashing](https://www.attrs.org/en/stable/hashing.html).
- The traversal of MROs when using multiple inheritance was backward:
If you defined a class `C` that subclasses `A` and `B` like `C(A, B)`, `attrs` would have collected the attributes from `B`*before* those of `A`.
This is now fixed and means that in classes that employ multiple inheritance, the output of `__repr__` and the order of positional arguments in `__init__` changes.
Because of the nature of this bug, a proper deprecation cycle was unfortunately impossible.
Generally speaking, it's advisable to prefer `kwargs`-based initialization anyways –*especially* if you employ multiple inheritance and diamond-shaped hierarchies.
- The `__repr__` set by `attrs` no longer produces an `AttributeError` when the instance is missing some of the specified attributes (either through deleting or after using `init=False` on some attributes).
This can break code that relied on `repr(attr_cls_instance)` raising `AttributeError` to check if any `attrs`-specified members were unset.
If you were using this, you can implement a custom method for checking this:
- Added new option *auto_attribs* to `@attr.s` that allows to collect annotated fields without setting them to `attr.ib()`.
Setting a field to an `attr.ib()` is still possible to supply options like validators.
Setting it to any other value is treated like it was passed as `attr.ib(default=value)` -- passing an instance of `attr.Factory` also works as expected.
To encourage more participation, the project has also been moved into a [dedicated GitHub organization](https://github.com/python-attrs/) and everyone is most welcome to join!
- Added `attr.evolve()` that, given an instance of an `attrs` class and field changes as keyword arguments, will instantiate a copy of the given instance with the changes applied.
`evolve()` replaces `assoc()`, which is now deprecated.
`evolve()` is significantly faster than `assoc()`, and requires the class have an initializer that can take the field values as keyword arguments (like `attrs` itself can generate).
- Added `@attr.s(str=True)` that will optionally create a `__str__()` method that is identical to `__repr__()`.
This is mainly useful with `Exception`s and other classes that rely on a useful `__str__()` implementation but overwrite the default one through a poor own one.
Default Python class behavior is to use `__repr__()` as `__str__()` anyways.
If you tried using `attrs` with `Exception`s and were puzzled by the tracebacks: this option is for you.
-`__name__` is no longer overwritten with `__qualname__` for `attr.s(slots=True)` classes.
- All instances where function arguments were called `cl` have been changed to the more Pythonic `cls`.
Since it was always the first argument, it's doubtful anyone ever called those function with in the keyword form.
If so, sorry for any breakage but there's no practical deprecation path to solve this ugly wart.
### Deprecations:
- Accessing `Attribute` instances on class objects is now deprecated and will stop working in 2017.
If you need introspection please use the `__attrs_attrs__` attribute or the `attr.fields()` function that carry them too.
In the future, the attributes that are defined on the class body and are usually overwritten in your `__init__` method are simply removed after `@attr.s` has been applied.
This will remove the confusing error message if you write your own `__init__` and forget to initialize some attribute.
Instead you will get a straightforward `AttributeError`.
In other words: decorated classes will work more like plain Python classes which was always `attrs`'s goal.
- The serious-business aliases `attr.attributes` and `attr.attr` have been deprecated in favor of `attr.attrs` and `attr.attrib` which are much more consistent and frankly obvious in hindsight.
They will be purged from documentation immediately but there are no plans to actually remove them.
### Changes:
-`attr.asdict()`'s `dict_factory` arguments is now propagated on recursion.
They may work by chance but any effort to keep them working has ceased.
The last Python 2.6 release was on October 29, 2013 and is no longer supported by the CPython core team.
Major Python packages like Django and Twisted dropped Python 2.6 a while ago already.
Python 3.3 never had a significant user base and wasn't part of any distribution's LTS release.
### Changes:
-`__slots__` have arrived!
Classes now can automatically be [slotted](https://docs.python.org/3/reference/datamodel.html#slots)-style (and save your precious memory) just by passing `slots=True`.