Skip to content

Releases: python-attrs/attrs

24.3.0

16 Dec 06:58
24.3.0
598494a
Compare
Choose a tag to compare

Highlights

Mostly bug fixes and adjustments, but also support for Python 3.13's copy.replace(). On the other side we say goodbye to Python 3.7.

Full changelog below!

Special Thanks

This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!

Above and Beyond

Variomedia AG (@variomedia), Tidelift (@tidelift), thanks.dev (@thnxdev), Klaviyo (@klaviyo), FilePreviews (@filepreviews), Privacy Solutions GmbH (@privacy-solutions), Daniel Fortunov (@asqui), Kevin P. Fleming (@kpfleming), and Polar (@polarsource).

Maintenance Sustainers

Buttondown (@buttondown), Konstantin Vinogradov (@vinogradovkonst), Christopher Dignam (@chdsbd), Stefan Hagen (@sthagen), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), Chris Withers (@cjw296), Mike Fiedler (@miketheman), Duncan Hill (@cricalix), Colin Marquardt (@cmarqu), Pieter Swinkels (@swinkels), Nick Libertini (@libertininick), Moving Content AG (@moving-content), ProteinQure (@ProteinQure), The Westervelt Company (@westerveltco), Sławomir Ehlert (@slafs), Mostafa Khalil (@khadrawy), Filip Mularczyk (@mukiblejlok), Thomas Klinger (@thmsklngr), Andreas Poehlmann (@ap--), August Bigelow (@atbigelow), Carlton Gibson (@carltongibson), and Roboflow (@roboflow).

Not to forget 9 more amazing humans who chose to be generous but anonymous!

Full Changelog

Backwards-incompatible Changes

  • Python 3.7 has been dropped. #1340

Changes

  • Introduce attrs.NothingType, for annotating types consistent with attrs.NOTHING. #1358
  • Allow mutating __suppress_context__ and __notes__ on frozen exceptions. #1365
  • attrs.converters.optional() works again when taking attrs.converters.pipe() or another Converter as its argument. #1372
  • attrs instances now support copy.replace(). #1383
  • attrs.validators.instance_of()'s type hints now allow for union types. For example: instance_of(str | int) #1385

This release contains contributions from @dwgrth, @esteevens, @filbranden, @geofft, @graingert, @hynek, @mschoettle, @Tinche, @tjstum, and @webknjaz.

Artifact Attestations

You can verify this release's artifact attestions using GitHub's CLI tool by downloading the sdist and wheel from PyPI and running:

$ gh attestation verify --owner python-attrs attrs-24.3.0.tar.gz

and

$ gh attestation verify --owner python-attrs attrs-24.3.0-py3-none-any.whl

24.2.0

06 Aug 14:36
24.2.0
6771a04
Compare
Choose a tag to compare

Highlights

Big releases always carry the risk of regressions, but never did I expect to break Python 3.14’s CI! On the plus side, attrs runs on 3.14 now.

Full changelog below!

Special Thanks

This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!

Above and Beyond

Variomedia AG (@variomedia), Tidelift (@tidelift), FilePreviews (@filepreviews), Klaviyo (@klaviyo), Daniel Fortunov (@asqui), and Kevin P. Fleming (@kpfleming).

Maintenance Sustainers

Adam Hill (@adamghill), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Moving Content AG (@moving-content), ProteinQure (@ProteinQure), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), The Westervelt Company (@westerveltco), Philippe Galvan (@PhilippeGalvan), Birk Jernström (@birkjernstrom), Chris Withers (@cjw296), Christopher Dignam (@chdsbd), Stefan Hagen (@sthagen), Sławomir Ehlert (@slafs), Mostafa Khalil (@khadrawy), Filip Mularczyk (@mukiblejlok), Mike Fiedler (@miketheman), Thomas Klinger (@thmsklngr), Duncan Hill (@cricalix), Colin Marquardt (@cmarqu), and Andreas Poehlmann (@ap--).

Not to forget 7 more amazing humans who chose to be generous but anonymous!

Full Changelog

Deprecations

  • Given the amount of warnings raised in the broader ecosystem, we've decided to only soft-deprecate the hash argument to @define / @attr.s. Please don't use it in new code, but we don't intend to remove it anymore. #1330

Changes

  • attrs.converters.pipe() (and its syntactic sugar of passing a list for attrs.field()'s / attr.ib()'s converter argument) works again when passing attrs.setters.convert to on_setattr (which is default for attrs.define). #1328
  • Restored support for PEP 649 / 749-implementing Pythons -- currently 3.14-dev. #1329

This release contains contributions from @hynek.

Artifact Attestations

You can verify this release's artifact attestions using GitHub's CLI tool by downloading the sdist and wheel from PyPI and running:

$ gh attestation verify --owner python-attrs attrs-24.2.0.tar.gz

and

$ gh attestation verify --owner python-attrs attrs-24.2.0-py3-none-any.whl

24.1.0

03 Aug 14:29
24.1.0
556ca7c
Compare
Choose a tag to compare

Highlights

This release comes severely delayed, but comes with many exciting new features, bugfixes, and performance optimizations!

The most notable is probably the possibility to receive self and field definitions in your converters by wrapping them into a attrs.Converter.

The other big thing is our own replacement for __init_subclass__ called (you guessed it) __attrs_init_subclass__. Check out the docs, if you're not sure what this is good for.

Finally, we've made more important steps to promote our "new" APIs (can you believe they're 4 years old!?) in the docs. If we missed anything, please let us know.

Full changelog below!

Special Thanks

This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!

Above and Beyond

Variomedia AG (@variomedia), Tidelift (@tidelift), FilePreviews (@filepreviews), Klaviyo (@klaviyo), Daniel Fortunov (@asqui), and Kevin P. Fleming (@kpfleming).

Maintenance Sustainers

Adam Hill (@adamghill), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Moving Content AG (@moving-content), ProteinQure (@ProteinQure), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), The Westervelt Company (@westerveltco), Philippe Galvan (@PhilippeGalvan), Birk Jernström (@birkjernstrom), Chris Withers (@cjw296), Christopher Dignam (@chdsbd), Stefan Hagen (@sthagen), Sławomir Ehlert (@slafs), Mostafa Khalil (@khadrawy), Filip Mularczyk (@mukiblejlok), Mike Fiedler (@miketheman), Thomas Klinger (@thmsklngr), Duncan Hill (@cricalix), Colin Marquardt (@cmarqu), and Andreas Poehlmann (@ap--).

Not to forget 7 more amazing humans who chose to be generous but anonymous!

Full Changelog

Backwards-incompatible Changes

  • attrs.evolve() doesn't accept the inst argument as a keyword argument anymore. Pass it as the first positional argument instead. #1264

  • attrs.validators.provides() has been removed. The removed code is available as a gist for convenient copy and pasting. #1265

  • All packaging metadata except from __version__ and __version_info__ has been removed from the attr and attrs modules (for example, attrs.__url__).

    Please use importlib.metadata or importlib_metadata instead. #1268

  • Speed up the generated __eq__ methods significantly by generating a chain of attribute comparisons instead of constructing and comparing tuples. This change arguably makes the behavior more correct, but changes it if an attribute compares equal by identity but not value, like float('nan'). #1310

Deprecations

  • The repr_ns argument to attr.s is now deprecated. It was a workaround for nested classes in Python 2 and is pointless in Python 3. #1263
  • The hash argument to @attr.s, @attrs.define, and make_class() is now deprecated in favor of unsafe_hash, as defined by PEP 681. #1323

Changes

  • Allow original slotted functools.cached_property classes to be cleaned by garbage collection. Allow super() calls in slotted cached properties. #1221

  • Our type stubs now use modern type notation and are organized such that VS Code's quick-fix prefers the attrs namespace. #1234

  • Preserve AttributeError raised by properties of slotted classes with functools.cached_properties. #1253

  • It is now possible to wrap a converter into an attrs.Converter and get the current instance and/or the current field definition passed into the converter callable.

    Note that this is not supported by any type checker, yet. #1267

  • attrs.make_class() now populates the __annotations__ dict of the generated class, so that attrs.resolve_types() can resolve them. #1285

  • Added the attrs.validators.or_() validator. #1303

  • The combination of a __attrs_pre_init__ that takes arguments, a kw-only field, and a default on that field does not crash anymore. #1319

  • attrs.validators.in_() now transforms certain unhashable options to tuples to keep the field hashable.

    This allows fields that use this validator to be used with, for example, attrs.filters.include(). #1320

  • If a class has an inherited method called __attrs_init_subclass__, it is now called once the class is done assembling.

    This is a replacement for Python's __init_subclass__ and useful for registering classes, and similar. #1321


This release contains contributions from @bibajz, @carltongibson, @diabolo-dan, @dlax, @econchick, @frenzymadness, @hynek, @koenigdavidmj, @mikejturner, @moto-timo, @my1e5, @richardsheridan, @sscherfke, @tdsmith, and @Tinche.

Artifact Attestations

You can verify this release's artififact attestions using GitHub's CLI tool by downloading the sdist and wheel from PyPI and running:

$ gh attestation verify --owner python-attrs attrs-24.1.0.tar.gz

and

$ gh attestation verify --owner python-attrs attrs-24.1.0-py3-none-any.whl

23.2.0

31 Dec 06:29
23.2.0
9e443b1
Compare
Choose a tag to compare

Highlights

Mostly typing fixes in this release, but I'm excited that we found a workaround to make functools.cached_property work with slotted classes! Also, I'm sure there's gonna be fans of the new behavior of __attrs_pre_init__ where it receives all arguments passed to __init__ if it accepts more than self.

Full changelog below!

Special Thanks

This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!

Above and Beyond

Variomedia AG (@variomedia), Tidelift (@tidelift), FilePreviews (@filepreviews), Daniel Fortunov (@asqui), and Kevin P. Fleming (@kpfleming).

Maintenance Sustainers

Adam Hill (@adamghill), Dan Groshev (@si14), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Moving Content AG (@moving-content), ProteinQure (@ProteinQure), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), Ionel Cristian Mărieș (@ionelmc), The Westervelt Company (@westerveltco), Philippe Galvan (@PhilippeGalvan), Birk Jernström (@birkjernstrom), Tim Schilling (@tim-schilling), Chris Withers (@cjw296), Christopher Dignam (@chdsbd), Stefan Hagen (@sthagen), Sławomir Ehlert (@slafs), Mostafa Khalil (@khadrawy), Filip Mularczyk (@mukiblejlok), and Mike Fiedler (@miketheman).

Not to forget 6 more amazing humans who chose to be generous but anonymous!

Full Changelog

Changes

  • The type annotation for attrs.resolve_types() is now correct. #1141
  • Type stubs now use typing.dataclass_transform to decorate dataclass-like decorators, instead of the non-standard __dataclass_transform__ special form, which is only supported by Pyright. #1158
  • Fixed serialization of namedtuple fields using attrs.asdict/astuple() with retain_collection_types=True. #1165
  • attrs.AttrsInstance is now a typing.Protocol in both type hints and code. This allows you to subclass it along with another Protocol. #1172
  • If attrs detects that __attrs_pre_init__ accepts more than just self, it will call it with the same arguments as __init__ was called. This allows you to, for example, pass arguments to super().__init__(). #1187
  • Slotted classes now transform functools.cached_property decorated methods to support equivalent semantics. #1200
  • Added class_body argument to attrs.make_class() to provide additional attributes for newly created classes. It is, for example, now possible to attach methods. #1203

23.1.0

16 Apr 10:45
23.1.0
1e2f6f9
Compare
Choose a tag to compare

Highlights

A lot of features and smaller bug fixes! But also with a heavy heart, we're leaving the last dataclass-less Python version (3.6) behind, but don't worry: the old versions aren't going anywhere and thanks to the magic of package metadata, pip install attrs should still work on Python 3.6 as if nothing happened.

Special Thanks

This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!

Above and Beyond

Variomedia AG (@variomedia), Tidelift (@tidelift), Sentry (@getsentry), HiredScore (@HiredScore), FilePreviews (@filepreviews), and Daniel Fortunov (@asqui).

Maintenance Sustainers

Adam Hill (@adamghill), Dan Groshev (@si14), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Moving Content AG (@moving-content), Stein Magnus Jodal (@jodal), ProteinQure (@ProteinQure), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), Tom Ballinger (@thomasballinger), @medecau, Ionel Cristian Mărieș (@ionelmc), The Westervelt Company (@westerveltco), Philippe Galvan (@PhilippeGalvan), Birk Jernström (@birkjernstrom), Tim Schilling (@tim-schilling), Chris Withers (@cjw296), Christopher Dignam (@chdsbd), and Stefan Hagen (@sthagen).

Not to forget 3 more amazing humans who chose to be generous but anonymous!

Full Changelog

Backwards-incompatible Changes

  • Python 3.6 has been dropped and packaging switched to static package data using Hatch. #993

Deprecations

  • The support for zope-interface via the attrs.validators.provides validator is now deprecated and will be removed in, or after, April 2024.

    The presence of a C-based package in our developement dependencies has caused headaches and we're not under the impression it's used a lot.

    Let us know if you're using it and we might publish it as a separate package. #1120

Changes

  • attrs.filters.exclude() and attrs.filters.include() now support the passing of attribute names as strings. #1068

  • attrs.has() and attrs.fields() now handle generic classes correctly. #1079

  • Fix frozen exception classes when raised within e.g. contextlib.contextmanager, which mutates their __traceback__ attributes. #1081

  • @frozen now works with type checkers that implement PEP-681 (ex. pyright). #1084

  • Restored ability to unpickle instances pickled before 22.2.0. #1085

  • attrs.asdict()'s and attrs.astuple()'s type stubs now accept the attrs.AttrsInstance protocol. #1090

  • Fix slots class cellvar updating closure in CPython 3.8+ even when __code__ introspection is unavailable. #1092

  • attrs.resolve_types() can now pass include_extras to typing.get_type_hints() on Python 3.9+, and does so by default. #1099

  • Added instructions for pull request workflow to CONTRIBUTING.md. #1105

  • Added type parameter to attrs.field() function for use with attrs.make_class().

    Please note that type checkers ignore type metadata passed into make_class(), but it can be useful if you're wrapping attrs. #1107

  • It is now possible for attrs.evolve() (and attr.evolve()) to change fields named inst if the instance is passed as a positional argument.

    Passing the instance using the inst keyword argument is now deprecated and will be removed in, or after, April 2024. #1117

  • attrs.validators.optional() now also accepts a tuple of validators (in addition to lists of validators). #1122

22.2.0

21 Dec 09:33
22.2.0
a9960de
Compare
Choose a tag to compare

Highlights

It's been a lot busier than the changelog indicates, but a lot of the work happened under the hood (like some impressive performance improvements). But we've got still one big new feature that's are worthy the holidays:

Fields now have an alias argument that allows you to set the field's name in the generated __init__ method. This is especially useful for those who aren't fans of attrs's behavior of stripping underscores from private attribute names.

Special Thanks

This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!

Above and Beyond

Variomedia AG (@variomedia), Tidelift (@tidelift), Sentry (@getsentry), HiredScore (@HiredScore), FilePreviews (@filepreviews), and Daniel Fortunov (@asqui).

Maintenance Sustainers

@rzijp, Adam Hill (@adamghill), Dan Groshev (@si14), Tamir Bahar (@tmr232), Adi Roiban (@adiroiban), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Moving Content AG (@moving-content), Stein Magnus Jodal (@jodal), Iwan Aucamp (@aucampia), ProteinQure (@ProteinQure), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), Thomas Ballinger (@thomasballinger), @medecau, Ionel Cristian Mărieș (@ionelmc), The Westervelt Company (@westerveltco), Philippe Galvan (@PhilippeGalvan), Birk Jernström (@birkjernstrom), Jannis Leidel (@jezdez), Tim Schilling (@tim-schilling), Chris Withers (@cjw296), and Christopher Dignam (@chdsbd).

Not to forget 2 more amazing humans who chose to be generous but anonymous!

Full Changelog

Backwards-incompatible Changes

  • Python 3.5 is not supported anymore. #988

Deprecations

  • Python 3.6 is now deprecated and support will be removed in the next release. #1017

Changes

  • 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 alias option can be use to override private attribute name mangling, or add other arbitrary field argument name overrides. #950

  • attrs.NOTHING is now an enum value, making it possible to use with e.g. typing.Literal. #983

  • Added missing re-import of attr.AttrsInstance to the attrs namespace. #987

  • Fix slight performance regression in classes with custom __setattr__ and speedup even more. #991

  • Class-creation performance improvements by switching performance-sensitive templating operations to f-strings.

    You can expect an improvement of about 5% -- even for very simple classes. #995

  • attrs.has() is now a TypeGuard for AttrsInstance. That means that type checkers know a class is an instance of an attrs class if you check it using attrs.has() (or attr.has()) first. #997

  • Made attrs.AttrsInstance stub available at runtime and fixed type errors related to the usage of attrs.AttrsInstance in Pyright. #999

  • On Python 3.10 and later, call abc.update_abstractmethods() on dict classes after creation. This improves the detection of abstractness. #1001

  • attrs's pickling methods now use dicts instead of tuples. That is safer and more robust across different versions of a class. #1009

  • 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). #1010

  • The type stubs for attrs.cmp_using() now have default values. #1027

  • To conform with PEP 681, attr.s() and attrs.define() now accept unsafe_hash in addition to hash. #1065

22.1.0

28 Jul 13:27
22.1.0
Compare
Choose a tag to compare

Highlights

The main features of this release are:

  • The departure of Python 2.7 (enjoy your retirement!),
  • and the arrival of Python 3.11.

We had loftier goals feature-wise, but didn't want to block others embracing Python 3.11.

❤️ Huge thanks to my GitHub sponsors, Tidelift subscribers, and Ko-fi buyers! ❤️

None of my projects would exist in their current form without you!

Full Changelog

Backwards-incompatible Changes

  • Python 2.7 is not supported anymore.

    Dealing with Python 2.7 tooling has become too difficult for a volunteer-run project.

    We have supported Python 2 more than 2 years after it was officially discontinued and feel that we have paid our dues. All version up to 21.4.0 from December 2021 remain fully functional, of course. #936

  • The deprecated cmp attribute of attrs.Attribute has been removed. This does not affect the cmp argument to attr.s that can be used as a shortcut to set eq and order at the same time. #939

Changes

  • Instantiation of frozen slotted classes is now faster. #898
  • If an eq key is defined, it is also used before hashing the attribute. #909
  • Added attrs.validators.min_len(). #916
  • attrs.validators.deep_iterable()'s member_validator argument now also accepts a list of validators and wraps them in an attrs.validators.and_(). #925
  • Added missing type stub re-imports for attrs.converters and attrs.filters. #931
  • Added missing stub for attr(s).cmp_using(). #949
  • attrs.validators._in()'s ValueError is not missing the attribute, expected options, and the value it got anymore. #951
  • Python 3.11 is now officially supported. #969

21.4.0

29 Dec 13:21
21.4.0
Compare
Choose a tag to compare

This is a quick bug fix release for a regression that causes coverage report fail under certain circumstances.

Full Changelog

Changes

  • Fixed the test suite on PyPy3.8 where cloudpickle does not work. #892
  • Fixed coverage report for projects that use attrs and don't set a --source. #895, #896

21.3.0

28 Dec 06:58
21.3.0
Compare
Choose a tag to compare

This is a big release in the history of attrs and finishes an arc that took way too long and also delayed this very overdue release. But it's done: import attrs that has been talked about for years1, but fell victim to “just this one more thing” has finally landed.

From now on, modern attrs code looks like this:

from attrs import define

@define
class HelloWorld:
    modern: bool = True

The define/field APIs have been around for over a year and were very popular, now the rest of the package followed suit. I'm very excited that attrs remains relevant and keeps evolving over now more than half a decade. If you're curious about some of the background, the docs now contain a short explanation and history lesson. As long as our users keep pushing us, we will keep pushing forward class generation in Python!

Big thanks to my GitHub Sponsors, Tidelift subscribers, and Ko-fi buyers that help me mustering the motivation for such long-running project!


Since the release took so long, there's more highlights than we can enumerate here, we'd just like to point out a breaking change in the new APIs: converters now run on setting attributes by default. If this is causing problems to you, you can disable that behavior by setting @define(on_setattr=[]).

Full Changelog

Backward-incompatible Changes

  • 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. #835, #886

  • import attrs has finally landed! As of this release, you can finally import attrs using its proper name.

    Not all names from the attr namespace have been transferred; most notably attr.s and attr.ib are missing. See attrs.define and attrs.field if you haven't seen our next-generation APIs yet. A more elaborate explanation can be found On The Core API Names

    This feature is at least for one release provisional. We don't plan on changing anything, but such a big change is unlikely to go perfectly on the first strike.

    The API docs have been mostly updated, but it will be an ongoing effort to change everything to the new APIs. Please note that we have not moved -- or even removed -- anything from attr!

    Please do report any bugs or documentation inconsistencies! #887

Changes

  • attr.asdict(retain_collection_types=False) (default) dumps collection-esque keys as tuples. #646, #888
  • __match_args__ are now generated to support Python 3.10's Structural Pattern Matching. This can be controlled by the match_args argument to the class decorators on Python 3.10 and later. On older versions, it is never added and the argument is ignored. #815
  • 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. #817
  • The generated __repr__ is significantly faster on Pythons with f-strings. #819
  • Attributes transformed via field_transformer are wrapped with AttrsClass again. #824
  • Generated source code is now cached more efficiently for identical classes. #828
  • Added attrs.converters.to_bool(). #830
  • attrs.resolve_types() now resolves types of subclasses after the parents are resolved. #842 #843
  • Added new validators: lt(val) (< val), le(va) (≤ val), ge(val) (≥ val), gt(val) (> val), and maxlen(n). #845
  • attrs classes are now fully compatible with cloudpickle (no need to disable repr anymore). #857
  • Added new context manager attrs.validators.disabled() and functions attrs.validators.(set|get)_disabled(). They deprecate attrs.(set|get)_run_validators(). All functions are interoperable and modify the same internal state. They are not – and never were – thread-safe, though. #859
  • attrs.validators.matches_re() now accepts pre-compiled regular expressions in addition to pattern strings. #877
  1. I have an issue from 2018 that I wanted to "come back the moment this lands".

21.2.0

07 May 09:39
21.2.0
Compare
Choose a tag to compare

Yesterday's 21.1.0 has unfortunately two regressions that we're fixing with today's 21.2.0 release:

  • The new recursive mode for attr.evolve() broke some use cases.
  • attrs is not importable under Python 3.4 anymore. While 3.4 hasn't been supported for a while now, we don't want it throw errors after installation.

We've reverted the changes to attr.evolve() and added packaging metadata blocking Python 3.4.

Additionally, we are yanking 21.1.0 from PyPI. If you've pinned attrs to 21.1.0, this does not affect you in any way.