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

Support for attr.has and attr.AttrsInstance #15980

Closed
koogoro opened this issue Aug 29, 2023 · 1 comment · Fixed by #15983
Closed

Support for attr.has and attr.AttrsInstance #15980

koogoro opened this issue Aug 29, 2023 · 1 comment · Fixed by #15983

Comments

@koogoro
Copy link
Collaborator

koogoro commented Aug 29, 2023

Feature
Recently, mypy added a plugin for attr.fields that tries to detect whether a type is an attr.s-decorated class, and reports an error if it isn't. However, attrs has a couple ways to check or annotate that a class is an attr.s-decorated class: attr.has and attr.AttrsInstance, neither of which seem to be supported by mypy right now.

attr.AttrsInstance is a protocol defined in the attrs internal stubs (https://github.com/python-attrs/attrs/blob/main/src/attr/__init__.pyi#L74) that represents that an object of an attr.s-decorated class. Right now, the plugin doesn't recognize attr.AttrsInstance, so it will report an error when trying to call e.g. attr.fields on a type[attr.AttrsInstance].

attr.has is a method that checks whether a class is attr.s-decorated. The plugin won't recognize this as a valid way to ensure attrs version 22.2.0 updated the internal stubs for attr.has to be a TypeGuard for type[attr.AttrsInstance]: (https://github.com/python-attrs/attrs/blob/main/src/attr/__init__.pyi#L541), so supporting attr.AttrsInstance may be sufficient when using sufficiently new stubs for attrs.

Pitch

A possible use for attr.has:

T = TypeVar('T')

def deserialize(attr_cls: type[T], value:bytes) -> T:
    assert attr.has(cls)
    fields = attr.fields(cls)
    ...

A possible use for attr.AttrsInstance:

T = TypeVar('T', bound=attr.AttrsInstance)

def deserialize(attr_cls: type[T], value: bytes) -> T:
    fields = attr.fields(attr_cls)
    ...
@koogoro
Copy link
Collaborator Author

koogoro commented Aug 29, 2023

@hauntsaninja this is the thing that I was having trouble with with the new behavior of the plugin. I think it probably counts as a feature request because we didn't really support these before either, we just wouldn't error on them because we didn't check the types around attr.fields.

hauntsaninja pushed a commit that referenced this issue Aug 30, 2023
Since python-attrs/attrs#890 (≥ 22.1.0)
`attrs.fields` is typed to accept a protocol.
Since python-attrs/attrs#997 (≥ 22.2.0)
`attrs.has` is a type-guard.

Support both by removing the explicit error reporting and letting it
fall through to the type stub.

Fixes #15980.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant