Skip to content

Feedback to next generation APIs #668

Closed

Description

@hynek

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:

Activity

  1. added this to the import attrs milestone on Aug 20, 2020
  2. pinned this issue on Aug 21, 2020
  3. rouge8 commented on Aug 21, 2020

    @rouge8
    Contributor

    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/python@3.8/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
  4. hynek commented on Aug 21, 2020

    @hynek
    MemberAuthor

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

  5. added a commit that references this issue on Aug 21, 2020
  6. euresti commented on Aug 22, 2020

    @euresti
    Contributor

    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)

  7. hynek commented on Aug 22, 2020

    @hynek
    MemberAuthor

    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. 🤔

  8. hynek commented on Aug 22, 2020

    @hynek
    MemberAuthor

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

  9. euresti commented on Aug 22, 2020

    @euresti
    Contributor

    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?

  10. hynek commented on Aug 22, 2020

    @hynek
    MemberAuthor

    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?

  11. euresti commented on Aug 22, 2020

    @euresti
    Contributor

    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.

  12. euresti commented on Aug 22, 2020

    @euresti
    Contributor

    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.

  13. hynek commented on Aug 22, 2020

    @hynek
    MemberAuthor

    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?

  14. euresti commented on Aug 22, 2020

    @euresti
    Contributor

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

  15. hynek commented on Aug 22, 2020

    @hynek
    MemberAuthor

    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.

  16. 15 remaining items

  17. euresti commented on Dec 25, 2020

    @euresti
    Contributor

    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.

  18. henryiii commented on Dec 25, 2020

    @henryiii

    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...)

  19. euresti commented on Dec 25, 2020

    @euresti
    Contributor

    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.

  20. henryiii commented on Dec 25, 2020

    @henryiii

    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.

  21. added a commit that references this issue on Apr 6, 2021
    6088149
  22. wsanchez commented on Apr 9, 2021

    @wsanchez

    Nice work, all

  23. unpinned this issue on May 4, 2021
  24. gatto commented on May 7, 2021

    @gatto

    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.

  25. hynek commented on May 7, 2021

    @hynek
    MemberAuthor

    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.

  26. gatto commented on May 7, 2021

    @gatto

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

  27. hynek commented on May 7, 2021

    @hynek
    MemberAuthor

    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.

  28. gatto commented on Oct 9, 2021

    @gatto

    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

Metadata

Metadata

Assignees

No one assigned

    Labels

    ThinkingNeeds more braining.

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions