-
-
Notifications
You must be signed in to change notification settings - Fork 374
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
pyright support via dataclass transforms #795
Comments
Yes, Eric was kind enough to reach out to me a few weeks ago and we discussed the topic. Their integration doesn't cover all of our features but it seems good enough – at least good enough to not deliver false positives. NG APIs should work too. I was hoping for feedback from @euresti (or any other typing gurus around here, really) before going to town on it. But maybe we can indeed squeeze it into 21.1 – at least provisionally. |
Also pulling in @Tinche who seems to have already played with it! |
Seems to work for me. The cost/benefit analysis seems in favor of adding this: it's very easy for us to do and IDE support is very useful, particularly if you're not quite ready to start using mypy. |
I've also verified this on an internal codebase and found it to be generally functional. Pleasantly, this allows us to implement I do feel that there's some value in having |
This is interesting. Similar to an idea I had for supporting this in python/mypy#5406 (comment) I wonder if this could be used in mypy itself. Might be complicated with all the caching mypy does, but ... maybe? |
How does it work with the overloads? Do you only annotate the real implementation? Can these be put in a .pyi file? |
@euresti did you get Eric’s e-mail? He sent it to your GitHub address. That would be the best way to get direct answers. :) |
Quick link to a gist-playground as well for interested parties: https://gist.github.com/asford/cd3c8ebbf245df6c3666eec0852c171d |
If someone wants to give it a shot, it would be great to squeeze this into the overdue 21.1 release that will come out next week come hell or high water. Seems like enough of y'all have played with it so I'd be delighted if y'all could cooperate on getting it done. :) |
I threw a very minimal PR together at #796 IFF you would like to fast-track support for this provisionally in 21.1. |
@jakebailey just pointed out something that I had missed previously. It appears that from typing import List
import attr
@attr.s(auto_attribs=True)
class SomeClass:
a_number: int = 42
list_of_numbers: List[int] = attr.field(factory=list) I can think of two solutions here:
I don't like option 2 because it would be an attrs-specific accommodation to the spec. What do you think about option 1? Can you think of any other options I'm missing? |
So in this case it would be really nice if we could go with option 2 (if making it configurable is out of the question). I know that my code bases are full of the "sweet" alternative and I'd hate to change it to the long one. |
@erictraut is there anything we can do, to move the |
Would you consider adding support for the parameter name I've been capturing all of the limitations in the spec as we discover them. After we've received feedback for a few months, I plan to go back and do a rev on the spec and the reference implementation. |
Supporting both in attrs is definitely an option, but there's a huge amount of code bases that use the shorter way (including mine). The thing with "demand" is that I really don't want to send a mob your way. I saw it play out with the current pydantic/delayed type annotations kerfuffle and I'm still disgusted by how it played out. I guess the lack of power-mongering is a weakness of mine, but I would prefer a solution that's good for everyone. What if attrs added As for your limitations: I think it's worth mentioning |
Keep in mind that the more attrs-specific accommodations that I add to the spec, the tougher it will be to standardize it in PEP form. I've already received a fair amount of pushback on the proposal in the typing-sig. If the goal is to standardize this (and I still think that's desirable), then I want to be cautious about adding more "warts" that will be difficult to justify to the typing-sig and python-sig reviewers. On the other hand, if we decide that we're not going to try to standardize this, then it will remain a pyright-specific mechanism. In that event, we have more flexibility to extend it. However, it's also less likely that attrs users with large existing code bases (like you) will be affected because they presumably started with mypy and are unlikely to switch to another type checker. If you're willing to add When you say |
A random user of both packages here: I'd prefer partial support released sooner to full support released later 🙏🏿 |
I found that using private attributes. (i.e attributes that start with a _) causes pyright to miss them in the constructor. @attr.s(auto_attribs=True)
class Class:
_priv: Int = None
A = Class(priv=1) # pyright errors saying No parameter named "priv"
B = Class(_priv=1) # no pyright errors. But is an actual error. |
Private attributes are not a standard behavior in dataclass, and they're not supported in the "dataclass transform" mechanism. This is one of several known limitations. If you want to use attrs with pyright, you would need to avoid using the private attribute mechanism. Another option is to explicitly specify an alias using a field descriptor. |
Thank you for the link. I didn't dig deep enough in the attrs documentation it seems. Can you point me to an example of using the alias in the field descriptor? I am not finding any examples. |
As a follow-up for those tracking this issued, support for |
Pyright doesn't support the import attr
@attr.define
class Thing:
x: int = attr.field()
@x.validator # error: member "validator" is unknown
def _check_x(self, attribute, value):
pass |
Are there any plans to add support for attrs |
This is a random comment (well, it certainly relates to |
In a similar vein to @emretech's issue, fields that have the default value generated by a method also have pyright treat it as an instance of "str" and not the attributes offered by import attr
@attr.define
class Thing:
"""Thing."""
a_num: int = attr.field(default=3)
b_num: int = attr.field() # Pyright: Fields without default values cannot appear after fields with default values
@b_num.default # Pyright: Cannot access member "default" for type "int" Member "default" is unknown
def _b_default(self) -> int:
"""Defaults b_num as double of a_num."""
return self.a_num * 2 This is how documentation suggests to use the default decorator, with the example provided causing the same message to be reported for attrs 23.2.0 and pyright 1.1.351. |
Not sure when this happened, but it seems that However there is one quirk that screws up a larger project of mine, namely that type variable resolution is partially broken when using a converter: from typing import Generic, TypeVar
from attrs import field, frozen
from typing_extensions import reveal_type
T = TypeVar("T")
@frozen
class Base(Generic[T]):
data: set[T] = field()
@frozen
class BaseConverted(Generic[T]):
data: set[T] = field(converter=set)
reveal_type(Base({1, 2})) # Type of "Base(1, 2)" is "Base[int]"
reveal_type(Base({1, 2}).data) # Type of "Base(1, 2).data" is "set[int]"
reveal_type(BaseConverted([1, 2])) # Type of "BaseConverted([1, 2])" is "BaseConverted[int]"
reveal_type(BaseConverted([1, 2]).data) # Type of "BaseConverted([1, 2]).data" is "set[T@BaseConverted]" Interestingly, the type variable for the class itself is correctly resolved in both cases, however for the field it is not: it is still at EDIT: mypy actually does this right, but only if the converter is pulled out as a separate standalone function, following mypy's caveat section |
@erictraut I am actually one of those start-with-mypy-switch-to-pyright users. I got convinced a while ago by this official type checker comparison. Keep up the good work 👏 |
pyright
is adding support forattrs
classes in static type checking through a source-level extension mechanism called dataclass transforms. This will provide support the strict-subset ofattrs
class semantics implemented as standard-librarydataclasses
inpyright
, and by extensionpylance
and VS Code.Relevant project issues include:
microsoft/pyright#1782 - Discussion thread for feature
microsoft/pylance-release#226 -
pylance
tracking issue.microsoft/pyright#146 -
pyright
ur-issue.microsoft/pyright#1773 - Initial PR
https://github.com/microsoft/pyright/blob/master/specs/dataclass_transforms.md - Current spec in master
Would y'all be open to a PR implemented the recommendations in the linked specification?
Perhaps there's a dialog to be had to ensure that the upcoming next-gen decorator semantics can be supported via this extension mechanism? (I don't have enough of the picture in mind to understand whether this is true.)
edit - Updating cross-refs I'd originally missed and rephrasing description. This connection had already been made!
The text was updated successfully, but these errors were encountered: