Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feedback to next generation APIs #668

Closed
hynek opened this issue Aug 20, 2020 · 35 comments · Fixed by #786
Closed

Feedback to next generation APIs #668

hynek opened this issue Aug 20, 2020 · 35 comments · Fixed by #786
Labels
Thinking Needs more braining.
Milestone

Comments

@hynek
Copy link
Member

hynek commented Aug 20, 2020

This is the issue to discuss the defaults and behavior of attr.define(), attr.mutable(), and attr.frozen() before they are finalized inside the new attrs namespace.

Feedback that we find justified will be spun out into separate issues.

Known issues:

@hynek hynek added this to the import attrs milestone Aug 20, 2020
@hynek hynek pinned this issue Aug 21, 2020
@rouge8
Copy link
Contributor

rouge8 commented Aug 21, 2020

Overall I love the new APIs. When updating some code to use @attr.define instead of @attr.s(auto_attribs=True), I was surprised by one behavior of slotted classes -- you don't seem to be able to use unittest.mock.patch.object() on methods on instances of slotted classes. It's not a result of anything in attrs (in the code snippet below I don't use attrs at all), but it might be worth noting in the docs since making slots=True the default behavior means attrs will be how many people encounter this for the first time.

import unittest.mock

class Slotted:
    __slots__ = ()

    def method(self):
        return 1

s = Slotted()
assert s.method() == 1

with unittest.mock.patch.object(s, "method", return_value=3):
    assert s.method() == 3

# Errors with:
# Traceback (most recent call last):
#   File "/usr/local/Cellar/[email protected]/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/unittest/mock.py", line 1490, in __enter__
#     setattr(self.target, self.attribute, new_attr)
# AttributeError: 'Slotted' object attribute 'method' is read-only

@hynek
Copy link
Member Author

hynek commented Aug 21, 2020

Ah yeah, thanks for that reminder, I will add it to the glossary!

hynek added a commit that referenced this issue Aug 21, 2020
ref #668

Signed-off-by: Hynek Schlawack <[email protected]>
@euresti
Copy link
Contributor

euresti commented Aug 22, 2020

Hmm. I'm not sure I like the hybrid behavior.

Imagine I forget to annotate something. Now instead of getting a nice error at import time I have to wait until I try to create something.

from attr import define, field

@define()
class A:
    x: int
    y = field(8)

Oh this case is actually pretty bad because I might not catch it even if i do A(8)

@hynek
Copy link
Member Author

hynek commented Aug 22, 2020

I thought about this for a while too.

I decided it’s worth the comfort because the only possible confusing error state is the one you describe and it’s impossible to miss even short-term when an attribute is missing. I’m open to being convinced otherwise but ISTM that in practice this trade-off is worth it. 🤔

@hynek
Copy link
Member Author

hynek commented Aug 22, 2020

How about the following: auto_attrib=None = Hybrid, everything else means what it means now?

@euresti
Copy link
Contributor

euresti commented Aug 22, 2020

What's the default value? (I suggest auto_attribs=True but that's my personal preference because I always write type annotated code)

I'd also like it if auto_attrib=None would raise if it found a mixture of attribs and annotations. Is it ok to add this to _transform_attrs or is affecting attr.s not something we should do?

@hynek
Copy link
Member Author

hynek commented Aug 22, 2020

What's the default value? (I suggest auto_attribs=True but that's my personal preference because I always write type annotated code)

I'd also like it if auto_attrib=None would raise if it found a mixture of attribs and annotations. Is it ok to add this to _transform_attrs or is affecting attr.s not something we should do?

Well None would be default which means “guess”. I’m Camp True too, but I don’t want to punish the typing haters for whine attrs is currently the only refuge.

I don’t thing an error on a mix of attr.ib and annotations is feasible because there a valid use cases for that. Maybe raise an error but add an option to override it?

@euresti
Copy link
Contributor

euresti commented Aug 22, 2020

I don't really see a good use for this:

@define()
class A:
    x: int
    y = field(8)

A.x won't exist and you won't be able to add it because of __slots__. Worst of all, mypy will think it exists.

Perhaps this could be ok:

@define()
class A:
    x: int = 72
    y = field(8)

But one could argue that it should be:

@define()
class A:
    x: ClassVar[int] = 72
    y = field(8)

Because it's gonna be a Class attribute not an instance one.

@euresti
Copy link
Contributor

euresti commented Aug 22, 2020

Oh and thinking about it more auto_attribs=None is a fine default value. Because if I use annotations they'll work the way I want them. (i.e. I don't have to add auto_attribs=True everywhere.

@hynek
Copy link
Member Author

hynek commented Aug 22, 2020

To be clear: it’s 100% not gonna be necessary to pass slots=True or auto_attribs=True because that’s my settings. 😅 The q now is how to handle your scenario. Truth to be told we can raise an error and when someone complains, we can still add an option to allow for it?

@euresti
Copy link
Contributor

euresti commented Aug 22, 2020

That option could be auto_attribs=False. :) Or did you want some kind of global disable?

@hynek
Copy link
Member Author

hynek commented Aug 22, 2020

God No 😅! I’m just trying to find a way where the common use case is not passing anything and it just works – ideally without exposing the users to sharp edges.

@euresti
Copy link
Contributor

euresti commented Aug 22, 2020

Just did a quick regex change on our code base, looking for trouble. I did find 2 interesting issues:

  1. A blind replace of attr.dataclass with attr.define yielded this which raises an error.
@attr.define(frozen=True)
class Base:
   ...

ValueError: Frozen classes can't use on_setattr.

  1. So I updated it to @attr.frozen. But then I hit another error:
@attr.frozen
class Base:
 ...

@attr.define
class Child(Base):
   ...

ValueError: Frozen classes can't use on_setattr.
This time on Child.

So one just has to treat frozen=True as a special case. Not a big thing but since we're talking about how the API feels.

@euresti
Copy link
Contributor

euresti commented Aug 22, 2020

I'm working on the mypy plugin but I am gonna need to know the final answer on how "hybrid" mode wants to work if there are both annotations and attribs. I think the options are:

  1. Take only the ones that have = attr.ib()
  2. Take only the annotated ones.
  3. Take both.
  4. Raise an exception.

Hmm. I thought #3 would be easy to implement (just don't raise the error) but it turns out we can't tell the order between annotated and un-annotated attributes.

class A:
   x: int
   y = attr.ib()

cls.__annotations__  ->   [x]
cls.__dict__.keys(). -> [y]

But which is actually first?

#2 is kind of a weird one. Why throw away those attr.ib()s?
#1 is relatively easy to implement. Because it's just a try catch.
#4 Might require the user to add ClassVar in order to add it.

Oh I should note that I think this should still be fine:

@define
class A:
   x: int = field()
   y = field()

We shouldn't force you to have to annotate everything.
Hmm. That might make 4 harder to implement. :)

@hynek
Copy link
Member Author

hynek commented Aug 23, 2020

Just did a quick regex change on our code base, looking for trouble. I did find 2 interesting issues:

  1. A blind replace of attr.dataclass with attr.define yielded this which raises an error.
@attr.define(frozen=True)
class Base:
   ...

ValueError: Frozen classes can't use on_setattr.

  1. So I updated it to @attr.frozen. But then I hit another error:
@attr.frozen
class Base:
 ...

@attr.define
class Child(Base):
   ...

ValueError: Frozen classes can't use on_setattr.
This time on Child.

So one just has to treat frozen=True as a special case. Not a big thing but since we're talking about how the API feels.

Oof, both aren't great.

I guess we should set on_setattr=None and only use the default if the class isn't effectively frozen?

@hynek
Copy link
Member Author

hynek commented Aug 23, 2020

(I have moved the hybrid discussion to #676 since it's non-trivial and also very important)

@wsanchez wsanchez added the Thinking Needs more braining. label Sep 1, 2020
aio-libs-github-bot bot pushed a commit to aio-libs/aiohttp that referenced this issue Nov 6, 2020
Bumps [attrs](https://github.com/python-attrs/attrs) from 20.2.0 to 20.3.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/python-attrs/attrs/releases">attrs's releases</a>.</em></p>
<blockquote>
<h2>20.3.0</h2>
<h2>Backward-incompatible Changes</h2>
<ul>
<li>
<p><code>attr.define()</code>, <code>attr.frozen()</code>, <code>attr.mutable()</code>, and <code>attr.field()</code> remain <strong>provisional</strong>.</p>
<p>This release does <strong>not</strong> change change anything about them and they are already used widely in production though.</p>
<p>If you wish to use them together with mypy, you can simply drop <a href="https://gist.github.com/hynek/1e3844d0c99e479e716169034b5fa963#file-attrs_ng_plugin-py">this plugin</a> into your project.</p>
<p>Feel free to provide feedback to them in the linked issue <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/668">#668</a>.</p>
<p>We will release the <code>attrs</code> namespace once we have the feeling that the APIs have properly settled. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/668">#668</a></p>
</li>
</ul>
<h2>Changes</h2>
<ul>
<li><code>attr.s()</code> now has a <em>field_transformer</em> hook that is called for all <code>Attribute</code>s and returns a (modified or updated) list of <code>Attribute</code> instances. <code>attr.asdict()</code> has a <em>value_serializer</em> hook that can change the way values are converted. Both hooks are meant to help with data (de-)serialization workflows. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/653">#653</a></li>
<li><code>kw_only=True</code> now works on Python 2. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/700">#700</a></li>
<li><code>raise from</code> now works on frozen classes on PyPy. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/703">#703</a>, <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/712">#712</a></li>
<li><code>attr.asdict()</code> and <code>attr.astuple()</code> now treat <code>frozenset</code>s like <code>set</code>s with regards to the <em>retain_collection_types</em> argument. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/704">#704</a></li>
<li>The type stubs for <code>attr.s()</code> and <code>attr.make_class()</code> are not missing the <em>collect_by_mro</em> argument anymore. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/711">#711</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/python-attrs/attrs/blob/master/CHANGELOG.rst">attrs's changelog</a>.</em></p>
<blockquote>
<h2>20.3.0 (2020-11-05)</h2>
<p>Backward-incompatible Changes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^</p>
<ul>
<li>
<p><code>attr.define()</code>, <code>attr.frozen()</code>, <code>attr.mutable()</code>, and <code>attr.field()</code> remain <strong>provisional</strong>.</p>
<p>This release does <strong>not</strong> change change anything about them and they are already used widely in production though.</p>
<p>If you wish to use them together with mypy, you can simply drop <code>this plugin &lt;https://gist.github.com/hynek/1e3844d0c99e479e716169034b5fa963#file-attrs_ng_plugin-py&gt;</code>_ into your project.</p>
<p>Feel free to provide feedback to them in the linked issue <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/668">#668</a>.</p>
<p>We will release the <code>attrs</code> namespace once we have the feeling that the APIs have properly settled.
<code>[#668](python-attrs/attrs#668) &lt;https://github.com/python-attrs/attrs/issues/668&gt;</code>_</p>
</li>
</ul>
<p>Changes
^^^^^^^</p>
<ul>
<li><code>attr.s()</code> now has a <em>field_transformer</em> hook that is called for all <code>Attribute</code>\ s and returns a (modified or updated) list of <code>Attribute</code> instances.
<code>attr.asdict()</code> has a <em>value_serializer</em> hook that can change the way values are converted.
Both hooks are meant to help with data (de-)serialization workflows.
<code>[#653](python-attrs/attrs#653) &lt;https://github.com/python-attrs/attrs/issues/653&gt;</code>_</li>
<li><code>kw_only=True</code> now works on Python 2.
<code>[#700](python-attrs/attrs#700) &lt;https://github.com/python-attrs/attrs/issues/700&gt;</code>_</li>
<li><code>raise from</code> now works on frozen classes on PyPy.
<code>[#703](python-attrs/attrs#703) &lt;https://github.com/python-attrs/attrs/issues/703&gt;</code><em>,
<code>[#712](python-attrs/attrs#712) &lt;https://github.com/python-attrs/attrs/issues/712&gt;</code></em></li>
<li><code>attr.asdict()</code> and <code>attr.astuple()</code> now treat <code>frozenset</code>\ s like <code>set</code>\ s with regards to the <em>retain_collection_types</em> argument.
<code>[#704](python-attrs/attrs#704) &lt;https://github.com/python-attrs/attrs/issues/704&gt;</code>_</li>
<li>The type stubs for <code>attr.s()</code> and <code>attr.make_class()</code> are not missing the <em>collect_by_mro</em> argument anymore.
<code>[#711](python-attrs/attrs#711) &lt;https://github.com/python-attrs/attrs/issues/711&gt;</code>_</li>
</ul>
<hr />
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/python-attrs/attrs/commit/f3762ba07bf0cec8bebdaaeca2212ba1d662ff13"><code>f3762ba</code></a> Prepare 20.3.0</li>
<li><a href="https://github.com/python-attrs/attrs/commit/3d66e5727b93d3463feb0fd780ae739192e7c363"><code>3d66e57</code></a> Exclude GitHub issues from linkcheck to avoid rate limits</li>
<li><a href="https://github.com/python-attrs/attrs/commit/06d0f8eda63b3f08cb5d94fff9fddf4fe6695621"><code>06d0f8e</code></a> Add funding URLs to metadata</li>
<li><a href="https://github.com/python-attrs/attrs/commit/d23924f765d09f77e87a5c51c1685df0d721b469"><code>d23924f</code></a> Add provisional notice</li>
<li><a href="https://github.com/python-attrs/attrs/commit/cd2f886d6372dca288abf9d999b3e35dacd9ced6"><code>cd2f886</code></a> Use 'i' and 'k' to better distinguish variables in an example (<a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/713">#713</a>)</li>
<li><a href="https://github.com/python-attrs/attrs/commit/f2dabeae82c75abe174aafc7a726481ded929872"><code>f2dabea</code></a> Fix exception chaining on PyPy (<a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/712">#712</a>)</li>
<li><a href="https://github.com/python-attrs/attrs/commit/6b4a1f1ce65162afe54e7101b263859bf8b2177e"><code>6b4a1f1</code></a> Tighten up mypy configuration</li>
<li><a href="https://github.com/python-attrs/attrs/commit/9f7d11e415bc789c9cbab255cb9a5b8903c1b122"><code>9f7d11e</code></a> Add types to collect_by_mro annotations m(</li>
<li><a href="https://github.com/python-attrs/attrs/commit/7020c8b5b55adefc76cf369fb071b1a4b15554a9"><code>7020c8b</code></a> pre-commit autoupdate</li>
<li><a href="https://github.com/python-attrs/attrs/commit/56c73081c5d767e30f529ac4f15a6bdd43e23d9f"><code>56c7308</code></a> Add missing collect_by_mro to typing stubs</li>
<li>Additional commits viewable in <a href="https://github.com/python-attrs/attrs/compare/20.2.0...20.3.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=attrs&package-manager=pip&previous-version=20.2.0&new-version=20.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/configuring-github-dependabot-security-updates)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
@Drino
Copy link
Contributor

Drino commented Nov 10, 2020

I've played around with new generation API a little, trying to migrate a part of my project onto it to feel the taste.

First of all - little classes work perfectly and with less boilerplate (I almost always use dataclass(frozen=True)), that's great :)

But it also feels like slotted classes are bad choice for my case

  • I sometimes use mixins to add a kw_only attrib (with converters and validators) to my class which results in multiple bases have instance lay-out conflict. I've ended up aliasing mixin = partial(define, slots=False, kw_only=True) for such classes, but I'm not sure if it's a great practice.
  • I've also run into an issue with property if it's used for init=False attributes - I've got my property descriptor overridden by auto-generated slot descriptor :(

I hope attr.s/attr.dataclass wouldn't be removed or some sane shortcuts for dict-classes would be provided :)

@hynek
Copy link
Member Author

hynek commented Nov 10, 2020

attr.s/attr.dataclass definitely aren't going anywhere.

@genric
Copy link

genric commented Dec 1, 2020

Hi,
Why attr.field kw_only default is False?

kw_only=False,

According to the docs(https://www.attrs.org/en/stable/api.html#attr.field) it should keyword-only, no? But it is the same as in:
kw_only=False,

@Drino
Copy link
Contributor

Drino commented Dec 1, 2020

Hi!
The documentation means that attr.field signature is keyword-only (all attributes are keyword-only - say, it's incorrect to write attr.field(5) and one should mention attribute name attr.field(default=5)).
The kw_only attribute default hadn't change and is False.

@genric
Copy link

genric commented Dec 1, 2020

Ah, ok :) I thought it was about kw_only being True by default(at least this is how I plan to use it most of the time). Thanks for clarification!

@Drino
Copy link
Contributor

Drino commented Dec 1, 2020

If your intention is to have a keyword-only constructor - you can use attr.s(kw_only=True) instead of passing argument to attr.ib manually all the time :)

@genric
Copy link

genric commented Dec 1, 2020

Yep 👍, just had some weird constructs to work around pos/kw args with the older versions of attrs, so now migrating them to fields ...
Thanks again! Next generation APIs look great! (maybe some minor doc improvement 😃 so people like me don't get confused)

@henryiii
Copy link

I'd second that, I thought it meant that changed for a second and was quite surprised at how large of a change would be, until I saw the * and guessed what it really meant.

@henryiii
Copy link

By the way, are the next gen APIs intentionally missing type info? Both define and field return Any, breaking the nice MyPy setup. Switching back to .ib and .s fixes it.

@euresti
Copy link
Contributor

euresti commented Dec 25, 2020

For field it shouldn't be returning Any there are overloads. Can you post the code of what you're seeing? As to define

mypy doesn't know about the new-style APIs yet and there's nothing we can do about it. However you can use this mypy plugin for now (for more details see https://www.attrs.org/en/stable/extending.html#wrapping-the-decorator). PR is submitted in python/mypy#9396.

The PR has been merged but there hasn't been a mypy release.

@henryiii
Copy link

henryiii commented Dec 25, 2020

Can you post the code of what you're seeing? As to define

Sure, I'm using pre-commit and mypy so don't have the original, but this minimal change back shows the problem: henryiii/hypernewsviewer#1

The problem seems to be field is missing type annotations too; so later on it returns "Any" because MyPy can't deduce anything about it.

The PR has been merged but there hasn't been a mypy release.

MyPy releases are a little slow sometimes. Python 3.9 style list[int] is in master but not in a release yet either... :'( (really waiting for the int | float 3.10 syntax, though...)

@euresti
Copy link
Contributor

euresti commented Dec 25, 2020

Oh I see. You need to install the attrs package in the same virtual env as mypy is running from. This is because attrs ships its own stubs. There are attrs stubs in typeshed (which is shipped with mypy) but they are older and we're thinking of just removing them entirely. I'm not too familar with poetry so I'm not sure if there's a different way to configure that.

@henryiii
Copy link

There are attrs stubs in typeshed

ahh, I bet that explains it. I am at least some of the time running via pre-commit, and I don’t have attrs in the extra dependencies there. Though I really thought I saw this both ways. I’ll check tomorrow, but I bet that’s the problem, I didn’t know it could partially work with no attrs installed.

@wsanchez
Copy link

wsanchez commented Apr 9, 2021

Nice work, all

commonism pushed a commit to commonism/aiohttp that referenced this issue Apr 27, 2021
Bumps [attrs](https://github.com/python-attrs/attrs) from 20.2.0 to 20.3.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/python-attrs/attrs/releases">attrs's releases</a>.</em></p>
<blockquote>
<h2>20.3.0</h2>
<h2>Backward-incompatible Changes</h2>
<ul>
<li>
<p><code>attr.define()</code>, <code>attr.frozen()</code>, <code>attr.mutable()</code>, and <code>attr.field()</code> remain <strong>provisional</strong>.</p>
<p>This release does <strong>not</strong> change change anything about them and they are already used widely in production though.</p>
<p>If you wish to use them together with mypy, you can simply drop <a href="https://gist.github.com/hynek/1e3844d0c99e479e716169034b5fa963#file-attrs_ng_plugin-py">this plugin</a> into your project.</p>
<p>Feel free to provide feedback to them in the linked issue <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/668">#668</a>.</p>
<p>We will release the <code>attrs</code> namespace once we have the feeling that the APIs have properly settled. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/668">#668</a></p>
</li>
</ul>
<h2>Changes</h2>
<ul>
<li><code>attr.s()</code> now has a <em>field_transformer</em> hook that is called for all <code>Attribute</code>s and returns a (modified or updated) list of <code>Attribute</code> instances. <code>attr.asdict()</code> has a <em>value_serializer</em> hook that can change the way values are converted. Both hooks are meant to help with data (de-)serialization workflows. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/653">#653</a></li>
<li><code>kw_only=True</code> now works on Python 2. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/700">#700</a></li>
<li><code>raise from</code> now works on frozen classes on PyPy. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/703">#703</a>, <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/712">#712</a></li>
<li><code>attr.asdict()</code> and <code>attr.astuple()</code> now treat <code>frozenset</code>s like <code>set</code>s with regards to the <em>retain_collection_types</em> argument. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/704">#704</a></li>
<li>The type stubs for <code>attr.s()</code> and <code>attr.make_class()</code> are not missing the <em>collect_by_mro</em> argument anymore. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/711">#711</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/python-attrs/attrs/blob/master/CHANGELOG.rst">attrs's changelog</a>.</em></p>
<blockquote>
<h2>20.3.0 (2020-11-05)</h2>
<p>Backward-incompatible Changes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^</p>
<ul>
<li>
<p><code>attr.define()</code>, <code>attr.frozen()</code>, <code>attr.mutable()</code>, and <code>attr.field()</code> remain <strong>provisional</strong>.</p>
<p>This release does <strong>not</strong> change change anything about them and they are already used widely in production though.</p>
<p>If you wish to use them together with mypy, you can simply drop <code>this plugin &lt;https://gist.github.com/hynek/1e3844d0c99e479e716169034b5fa963#file-attrs_ng_plugin-py&gt;</code>_ into your project.</p>
<p>Feel free to provide feedback to them in the linked issue <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/668">#668</a>.</p>
<p>We will release the <code>attrs</code> namespace once we have the feeling that the APIs have properly settled.
<code>[aio-libs#668](python-attrs/attrs#668) &lt;https://github.com/python-attrs/attrs/issues/668&gt;</code>_</p>
</li>
</ul>
<p>Changes
^^^^^^^</p>
<ul>
<li><code>attr.s()</code> now has a <em>field_transformer</em> hook that is called for all <code>Attribute</code>\ s and returns a (modified or updated) list of <code>Attribute</code> instances.
<code>attr.asdict()</code> has a <em>value_serializer</em> hook that can change the way values are converted.
Both hooks are meant to help with data (de-)serialization workflows.
<code>[aio-libs#653](python-attrs/attrs#653) &lt;https://github.com/python-attrs/attrs/issues/653&gt;</code>_</li>
<li><code>kw_only=True</code> now works on Python 2.
<code>[aio-libs#700](python-attrs/attrs#700) &lt;https://github.com/python-attrs/attrs/issues/700&gt;</code>_</li>
<li><code>raise from</code> now works on frozen classes on PyPy.
<code>[aio-libs#703](python-attrs/attrs#703) &lt;https://github.com/python-attrs/attrs/issues/703&gt;</code><em>,
<code>[aio-libs#712](python-attrs/attrs#712) &lt;https://github.com/python-attrs/attrs/issues/712&gt;</code></em></li>
<li><code>attr.asdict()</code> and <code>attr.astuple()</code> now treat <code>frozenset</code>\ s like <code>set</code>\ s with regards to the <em>retain_collection_types</em> argument.
<code>[aio-libs#704](python-attrs/attrs#704) &lt;https://github.com/python-attrs/attrs/issues/704&gt;</code>_</li>
<li>The type stubs for <code>attr.s()</code> and <code>attr.make_class()</code> are not missing the <em>collect_by_mro</em> argument anymore.
<code>[aio-libs#711](python-attrs/attrs#711) &lt;https://github.com/python-attrs/attrs/issues/711&gt;</code>_</li>
</ul>
<hr />
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/python-attrs/attrs/commit/f3762ba07bf0cec8bebdaaeca2212ba1d662ff13"><code>f3762ba</code></a> Prepare 20.3.0</li>
<li><a href="https://github.com/python-attrs/attrs/commit/3d66e5727b93d3463feb0fd780ae739192e7c363"><code>3d66e57</code></a> Exclude GitHub issues from linkcheck to avoid rate limits</li>
<li><a href="https://github.com/python-attrs/attrs/commit/06d0f8eda63b3f08cb5d94fff9fddf4fe6695621"><code>06d0f8e</code></a> Add funding URLs to metadata</li>
<li><a href="https://github.com/python-attrs/attrs/commit/d23924f765d09f77e87a5c51c1685df0d721b469"><code>d23924f</code></a> Add provisional notice</li>
<li><a href="https://github.com/python-attrs/attrs/commit/cd2f886d6372dca288abf9d999b3e35dacd9ced6"><code>cd2f886</code></a> Use 'i' and 'k' to better distinguish variables in an example (<a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/713">#713</a>)</li>
<li><a href="https://github.com/python-attrs/attrs/commit/f2dabeae82c75abe174aafc7a726481ded929872"><code>f2dabea</code></a> Fix exception chaining on PyPy (<a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/712">#712</a>)</li>
<li><a href="https://github.com/python-attrs/attrs/commit/6b4a1f1ce65162afe54e7101b263859bf8b2177e"><code>6b4a1f1</code></a> Tighten up mypy configuration</li>
<li><a href="https://github.com/python-attrs/attrs/commit/9f7d11e415bc789c9cbab255cb9a5b8903c1b122"><code>9f7d11e</code></a> Add types to collect_by_mro annotations m(</li>
<li><a href="https://github.com/python-attrs/attrs/commit/7020c8b5b55adefc76cf369fb071b1a4b15554a9"><code>7020c8b</code></a> pre-commit autoupdate</li>
<li><a href="https://github.com/python-attrs/attrs/commit/56c73081c5d767e30f529ac4f15a6bdd43e23d9f"><code>56c7308</code></a> Add missing collect_by_mro to typing stubs</li>
<li>Additional commits viewable in <a href="https://github.com/python-attrs/attrs/compare/20.2.0...20.3.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=attrs&package-manager=pip&previous-version=20.2.0&new-version=20.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/configuring-github-dependabot-security-updates)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
commonism pushed a commit to commonism/aiohttp that referenced this issue Apr 27, 2021
Bumps [attrs](https://github.com/python-attrs/attrs) from 20.2.0 to 20.3.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/python-attrs/attrs/releases">attrs's releases</a>.</em></p>
<blockquote>
<h2>20.3.0</h2>
<h2>Backward-incompatible Changes</h2>
<ul>
<li>
<p><code>attr.define()</code>, <code>attr.frozen()</code>, <code>attr.mutable()</code>, and <code>attr.field()</code> remain <strong>provisional</strong>.</p>
<p>This release does <strong>not</strong> change change anything about them and they are already used widely in production though.</p>
<p>If you wish to use them together with mypy, you can simply drop <a href="https://gist.github.com/hynek/1e3844d0c99e479e716169034b5fa963#file-attrs_ng_plugin-py">this plugin</a> into your project.</p>
<p>Feel free to provide feedback to them in the linked issue <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/668">#668</a>.</p>
<p>We will release the <code>attrs</code> namespace once we have the feeling that the APIs have properly settled. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/668">#668</a></p>
</li>
</ul>
<h2>Changes</h2>
<ul>
<li><code>attr.s()</code> now has a <em>field_transformer</em> hook that is called for all <code>Attribute</code>s and returns a (modified or updated) list of <code>Attribute</code> instances. <code>attr.asdict()</code> has a <em>value_serializer</em> hook that can change the way values are converted. Both hooks are meant to help with data (de-)serialization workflows. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/653">#653</a></li>
<li><code>kw_only=True</code> now works on Python 2. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/700">#700</a></li>
<li><code>raise from</code> now works on frozen classes on PyPy. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/703">#703</a>, <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/712">#712</a></li>
<li><code>attr.asdict()</code> and <code>attr.astuple()</code> now treat <code>frozenset</code>s like <code>set</code>s with regards to the <em>retain_collection_types</em> argument. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/704">#704</a></li>
<li>The type stubs for <code>attr.s()</code> and <code>attr.make_class()</code> are not missing the <em>collect_by_mro</em> argument anymore. <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/711">#711</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/python-attrs/attrs/blob/master/CHANGELOG.rst">attrs's changelog</a>.</em></p>
<blockquote>
<h2>20.3.0 (2020-11-05)</h2>
<p>Backward-incompatible Changes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^</p>
<ul>
<li>
<p><code>attr.define()</code>, <code>attr.frozen()</code>, <code>attr.mutable()</code>, and <code>attr.field()</code> remain <strong>provisional</strong>.</p>
<p>This release does <strong>not</strong> change change anything about them and they are already used widely in production though.</p>
<p>If you wish to use them together with mypy, you can simply drop <code>this plugin &lt;https://gist.github.com/hynek/1e3844d0c99e479e716169034b5fa963#file-attrs_ng_plugin-py&gt;</code>_ into your project.</p>
<p>Feel free to provide feedback to them in the linked issue <a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/668">#668</a>.</p>
<p>We will release the <code>attrs</code> namespace once we have the feeling that the APIs have properly settled.
<code>[aio-libs#668](python-attrs/attrs#668) &lt;https://github.com/python-attrs/attrs/issues/668&gt;</code>_</p>
</li>
</ul>
<p>Changes
^^^^^^^</p>
<ul>
<li><code>attr.s()</code> now has a <em>field_transformer</em> hook that is called for all <code>Attribute</code>\ s and returns a (modified or updated) list of <code>Attribute</code> instances.
<code>attr.asdict()</code> has a <em>value_serializer</em> hook that can change the way values are converted.
Both hooks are meant to help with data (de-)serialization workflows.
<code>[aio-libs#653](python-attrs/attrs#653) &lt;https://github.com/python-attrs/attrs/issues/653&gt;</code>_</li>
<li><code>kw_only=True</code> now works on Python 2.
<code>[aio-libs#700](python-attrs/attrs#700) &lt;https://github.com/python-attrs/attrs/issues/700&gt;</code>_</li>
<li><code>raise from</code> now works on frozen classes on PyPy.
<code>[aio-libs#703](python-attrs/attrs#703) &lt;https://github.com/python-attrs/attrs/issues/703&gt;</code><em>,
<code>[aio-libs#712](python-attrs/attrs#712) &lt;https://github.com/python-attrs/attrs/issues/712&gt;</code></em></li>
<li><code>attr.asdict()</code> and <code>attr.astuple()</code> now treat <code>frozenset</code>\ s like <code>set</code>\ s with regards to the <em>retain_collection_types</em> argument.
<code>[aio-libs#704](python-attrs/attrs#704) &lt;https://github.com/python-attrs/attrs/issues/704&gt;</code>_</li>
<li>The type stubs for <code>attr.s()</code> and <code>attr.make_class()</code> are not missing the <em>collect_by_mro</em> argument anymore.
<code>[aio-libs#711](python-attrs/attrs#711) &lt;https://github.com/python-attrs/attrs/issues/711&gt;</code>_</li>
</ul>
<hr />
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/python-attrs/attrs/commit/f3762ba07bf0cec8bebdaaeca2212ba1d662ff13"><code>f3762ba</code></a> Prepare 20.3.0</li>
<li><a href="https://github.com/python-attrs/attrs/commit/3d66e5727b93d3463feb0fd780ae739192e7c363"><code>3d66e57</code></a> Exclude GitHub issues from linkcheck to avoid rate limits</li>
<li><a href="https://github.com/python-attrs/attrs/commit/06d0f8eda63b3f08cb5d94fff9fddf4fe6695621"><code>06d0f8e</code></a> Add funding URLs to metadata</li>
<li><a href="https://github.com/python-attrs/attrs/commit/d23924f765d09f77e87a5c51c1685df0d721b469"><code>d23924f</code></a> Add provisional notice</li>
<li><a href="https://github.com/python-attrs/attrs/commit/cd2f886d6372dca288abf9d999b3e35dacd9ced6"><code>cd2f886</code></a> Use 'i' and 'k' to better distinguish variables in an example (<a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/713">#713</a>)</li>
<li><a href="https://github.com/python-attrs/attrs/commit/f2dabeae82c75abe174aafc7a726481ded929872"><code>f2dabea</code></a> Fix exception chaining on PyPy (<a href="https://github-redirect.dependabot.com/python-attrs/attrs/issues/712">#712</a>)</li>
<li><a href="https://github.com/python-attrs/attrs/commit/6b4a1f1ce65162afe54e7101b263859bf8b2177e"><code>6b4a1f1</code></a> Tighten up mypy configuration</li>
<li><a href="https://github.com/python-attrs/attrs/commit/9f7d11e415bc789c9cbab255cb9a5b8903c1b122"><code>9f7d11e</code></a> Add types to collect_by_mro annotations m(</li>
<li><a href="https://github.com/python-attrs/attrs/commit/7020c8b5b55adefc76cf369fb071b1a4b15554a9"><code>7020c8b</code></a> pre-commit autoupdate</li>
<li><a href="https://github.com/python-attrs/attrs/commit/56c73081c5d767e30f529ac4f15a6bdd43e23d9f"><code>56c7308</code></a> Add missing collect_by_mro to typing stubs</li>
<li>Additional commits viewable in <a href="https://github.com/python-attrs/attrs/compare/20.2.0...20.3.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=attrs&package-manager=pip&previous-version=20.2.0&new-version=20.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/configuring-github-dependabot-security-updates)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
@hynek hynek unpinned this issue May 4, 2021
@gatto
Copy link

gatto commented May 7, 2021

I like next generation APIs but I wish there was an example of their usage somewhere in the documentation! Thanks for the great work on attrs.

@hynek
Copy link
Member Author

hynek commented May 7, 2021

I plan to overhaul the docs for the next feature release to use primarily import attrs NG-style APIs.

I didn't want to mix them for now, to avoid confusion among less experienced readers.

@gatto
Copy link

gatto commented May 7, 2021

Sure, thank you @hynek, I guess I wanted to dive into NG since I'm just starting out to learn attrs these days anyways.

@hynek
Copy link
Member Author

hynek commented May 7, 2021

Yeah it’s a totally fair point. I have plastered examples all over announcements and somehow never added a full one to the docs. Which is a bummer since it doesn’t show off how pretty they are.

@gatto
Copy link

gatto commented Oct 9, 2021

I like next generation APIs but I wish there was an example of their usage somewhere in the documentation! Thanks for the great work on attrs.

Is there no news on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Thinking Needs more braining.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants