-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Use tuple[object, ...]
and dict[str, object]
as upper bounds for ParamSpec.args
and ParamSpec.kwargs
#12668
Conversation
Cc. @A5rocks as the |
This comment has been minimized.
This comment has been minimized.
6d8c3d4
to
5ff2309
Compare
This comment has been minimized.
This comment has been minimized.
1 similar comment
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this @AlexWaygood! It addresses one of the major issues left with the ParamSpec implementation, the other one being support for TypeAliases (#11855). The changes itself look simple enough.
Would be awesome if the PR could be included in 0.950, but it might be a bit too late for that 🤔
@@ -83,7 +83,7 @@ def changes_return_type_to_str(x: Callable[P, int]) -> Callable[P, str]: ... | |||
def returns_int(a: str, b: bool) -> int: ... | |||
|
|||
reveal_type(changes_return_type_to_str(returns_int)) # N: Revealed type is "def (a: builtins.str, b: builtins.bool) -> builtins.str" | |||
[builtins fixtures/tuple.pyi] | |||
[builtins fixtures/paramspec.pyi] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wondering, any particular reason not to use the new fixture for all ParamSpec tests? I noticed that a few where missing. Especially between L90 - L550.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used the new fixture in all the tests that broke with the changes made in this PR ;) They mostly broke because builtins.dict
is undefined in tuple.pyi
, but we need it for a lot of ParamSpec
-related tests if ParamSpec.kwargs
is bound to dict[str, Any]
.
There's no particular reason not to use them in all ParamSpec
tests -- but I wanted to keep the diff as small as possible, and the remaining tests don't need all the classes included in paramspec.pyi
. (I think it's best to use as minimal a fixture as possible, in most situations, to avoid slowing down the test suite.)
I wonder if the fallback types should be Since Pyre has the reference implementation for PEP 612, one option would be to check how it behaves and implement the same behavior (if it makes sense for mypy). |
I've no idea what Pyre does, I'll look into it! |
Okay, it looks like Pyre does indeed use |
Hmm, according to Pyre playground, however, Pyre doesn't acknowledge that |
I feel like |
…d/mypy into paramspec-args-kwargs
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Okay, |
tuple[Any, ...]
and dict[str, Any]
as upper bounds for ParamSpec.args
and ParamSpec.kwargs
tuple[object, ...]
and dict[str, object]
as upper bounds for ParamSpec.args
and ParamSpec.kwargs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good -- using object
is consistent with how we do things elsewhere. There is a style issue that would be nice to address -- I think that it just involves moving things around a bit.
mypy/types.py
Outdated
prefix: Optional['Parameters'] = None | ||
self, name: str, fullname: str, id: Union[TypeVarId, int], flavor: int, *, | ||
upper_bound: Optional[Type] = None, | ||
named_type_func: Optional[Callable[..., 'Instance']] = None, line: int = -1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently we at least mostly avoid calling back to the type checker in mypy.types
or mypy.nodes
(even through a callback), and I'd prefer to continue to maintain this principle, as a style issue. Also, it's better if constructors of essentially data objects such as types don't perform any non-trivial logic, such as calling get_fallback
.
What about defining a helper function in mypy.semanal_shared
that takes some of these arguments (named_type_func
etc.) and calculates the fallback? get_fallback
would be removed from here and would part of this helper function. You could name it calculate_param_spec_fallback
, for example, similar to calculate_tuple_fallback
that is already defined there.
Also, can you add argument types for the callback?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved the code into semanal_shared
-- although it could actually possibly be moved into typeanal
, since it seems paramspec args and paramspec kwargs are only ever constructed in typeanal
at the moment. (But perhaps that might change in the future -- what do you think?)
Moving the code into typeanal
would mean that we wouldn't have to use a callback protocol at all, the functions could just call self.named_type()
directly. But the functions might become more tightly coupled with the logic in typeanal.py
.
Diff from mypy_primer, showing the effect of this PR on open source code: core (https://github.com/home-assistant/core)
+ homeassistant/components/sonos/helpers.py:65: error: Unused "type: ignore" comment
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates! Looks good now.
@JukkaL thanks for the reviews! |
python/mypy#12668 Cherry-picked from #13521
python/mypy#12668 Cherry-picked from #13521
* Update mypy and mypy-zope * Unignore assigning to LogRecord attributes Presumably python/typeshed#8064 makes this ok Cherry-picked from #13521 * Remove unused ignores due to mypy ParamSpec fixes python/mypy#12668 Cherry-picked from #13521 * Remove additional unused ignores * Fix new mypy complaints related to `assertGreater` Presumably due to python/typeshed#8077 * Changelog * Reword changelog Co-authored-by: Patrick Cloke <clokep@users.noreply.github.com> Co-authored-by: Patrick Cloke <clokep@users.noreply.github.com>
Fixes #12386
Description
Mypy currently thinks that a variable annotated with
P.args
is not iterable, and thinks that a variable annotated withP.kwargs
does not have a.pop()
method:If we use
tuple[Any, ...]
as the upper bound ofParamSpec.args
, anddict[str, Any]
as the upper bound ofParamSpec.kwargs
, all these false-positive errors go away.Test Plan
Existing tests have been updated, and a test case has been added.
To avoid repetition among the
ParamSpec
test cases, I've added a newbuiltins
fixture,paramspec.pyi
, which basically combinestuple.pyi
anddict.pyi
.