-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
Reject invalid ParamSpec locations #18278
Reject invalid ParamSpec locations #18278
Conversation
…lysis - only bare paramspec binds.
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, I'm glad to see several bugs fixed. Looks good!
Actually, the home-assistant error might be false positive. Can you look at it? |
Amazing. I wasn't able to reproduce the problem on a local clone, and indeed it was apparently a glitch: another primer run did not produce an error there. |
This comment has been minimized.
This comment has been minimized.
No it wasn't a glitch. I just fixed it already after seeing your PR 😉
|
Ough! I was moderately certain that I reviewed primer hits and found them to be correct, but did not expect a fix in between... Please comment next time you do that!:) |
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.
This looks awesome! Makes things cleaner too.
I had one small nit regarding a test case
@@ -2144,7 +2165,7 @@ from typing_extensions import ParamSpec | |||
P= ParamSpec("P") | |||
T = TypeVar("T") | |||
|
|||
def smoke_testable(*args: P.args, **kwargs: P.kwargs) -> Callable[[Callable[P, T]], Type[T]]: | |||
def smoke_testable(*args: P.args, **kwargs: P.kwargs) -> Callable[[Callable[P, T]], Type[T]]: # E: ParamSpec "P" is unbound |
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.
this is functionality that mypy is losing, right? (you can see what it's going for in the interesting OtherClass example)
i think that's fine (and seems fine looking at the new primer warnings), but maybe we should clarify this test case? e.g. at least the comments are out of date
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! I've removed this test. This definition is not allowed by PEP612:
These “properties” can only be used as the annotated types for *args and **kwargs, accessed from a ParamSpec already in scope.
*args and **kwargs do not add a ParamSpec to the scope, so the test has never been conformant. IMO this is an extremely rare case: "given a set of arguments, produce a callable depending on those". I think dropping this implementation-defined extension to prevent silently accepting and misinterpreting invalid typing constructs is sensible.
… testParamSpecLocations
Diff from mypy_primer, showing the effect of this PR on open source code: altair (https://github.com/vega/altair)
+ altair/theme.py:251: error: ParamSpec "P" is unbound [valid-type]
prefect (https://github.com/PrefectHQ/prefect)
+ src/prefect/flows.py:1260: error: Arguments not allowed after ParamSpec.args [valid-type]
+ src/prefect/flows.py:1269: error: Arguments not allowed after ParamSpec.args [valid-type]
+ src/prefect/flows.py:1277: error: Arguments not allowed after ParamSpec.args [valid-type]
+ src/prefect/tasks.py:957: error: Arguments not allowed after ParamSpec.args [valid-type]
+ src/prefect/tasks.py:969: error: Arguments not allowed after ParamSpec.args [valid-type]
+ src/prefect/tasks.py:979: error: Arguments not allowed after ParamSpec.args [valid-type]
+ src/prefect/tasks.py:989: error: Arguments not allowed after ParamSpec.args [valid-type]
+ src/prefect/tasks.py:998: error: Arguments not allowed after ParamSpec.args [valid-type]
+ src/prefect/tasks.py:1043: error: Arguments not allowed after ParamSpec.args [valid-type]
+ src/prefect/tasks.py:1053: error: Arguments not allowed after ParamSpec.args [valid-type]
+ src/prefect/tasks.py:1063: error: Arguments not allowed after ParamSpec.args [valid-type]
+ src/prefect/tasks.py:1073: error: Arguments not allowed after ParamSpec.args [valid-type]
pwndbg (https://github.com/pwndbg/pwndbg)
+ pwndbg/gdblib/events.py: note: In function "connect":
+ pwndbg/gdblib/events.py:277: error: ParamSpec "P" is unbound [valid-type]
|
In the meantime |
Thank you! |
Hey (https://github.com/vega/altair) maintainer here Any advice on how to resolve this? |
Hello hello! There's nothing that puts P into scope / nothing that tells a type checker what P is meant to match. If you changed It's also unclear to me why you need an inner function at all. Seems like you could just |
Thanks @hauntsaninja for the quick response and help |
Hello, I'm facing issue with this PR since updating mypy: from typing import ParamSpec, Generic
P = ParamSpec("P")
class FunctionArgs(Generic[P]):
args: P.args
kwargs: P.kwargs def something(func: Callable[P, Any]) -> FunctionArgs[P]: ... $ mypy code.py
code.py:7:11: error: ParamSpec components are not allowed here [valid-type]
args: P.args
^
code.py:8:13: error: ParamSpec components are not allowed here [valid-type]
kwargs: P.kwargs I'm not sure if it's "compatible" with current typing PEPs/Spec, but this seems like a valid use case to me. |
This is not allowed by typing spec and has never been actually supported by
mypy: this PR only adds an explicit error for this invalid definition,
previously args and kwargs were (most likely) silently treated as Any.
As for the "why" bit: given an instance of FunctionArgs, we should be able
to assign some type to its attributes, including `args`. That is impossible
with ParamSpec, its components have no meaning separately. Given a
paramspec for `def fn(x: int) -> None`, both `args: tuple[int]; kwargs: {}`
and `args: tuple[()]; kwargs: {"x": int}` would be equally valid
resolutions, so the type of args is undefined. This can be supported as a
typechecker extension beyond the spec, of course, by requiring that args
and kwargs are only used together, but that would require special-casing
all class attributes similar to ParamSpec itself, and likely provides very
little ROI.
…On Wed, Feb 5, 2025, 14:17 Doctor ***@***.***> wrote:
Hello, I'm facing issue with this PR since updating mypy:
from typing import ParamSpec, Generic
P = ParamSpec("P")
class FunctionArgs(Generic[P]):
args: P.args
kwargs: P.kwargs
def something(func: Callable[P, Any]) -> FunctionArgs[P]: ...
$ mypy code.pycode.py:7:11: error: ParamSpec components are not allowed here [valid-type]
args: P.args
^code.py:8:13: error: ParamSpec components are not allowed here [valid-type]
kwargs: P.kwargs
I'm not sure if it's "compatible" with current typing PEPs/Spec, but this
seems like a valid use case to me.
—
Reply to this email directly, view it on GitHub
<#18278 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AMBQIRBOTLPVB4NLNBCCKHT2OIFQDAVCNFSM6AAAAABTMNWGGSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDMMZWHAZTEOBSHA>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
I see, so main issue is not being able to statically type it since function could be called differently, thanks. @dataclasses.dataclass(slots=True, kw_only=True, frozen=True)
class TaskInstance(Generic[P, TResult]):
task: TaskDefinition[P, TResult]
args: P.args
kwargs: P.kwargs
@dataclasses.dataclass(kw_only=True)
class TaskDefinition(Generic[P, TResult]):
func: Callable[P, Awaitable[TResult]]
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> TaskInstance[P, TResult]:
return TaskInstance(
task=self,
args=args,
kwargs=kwargs,
) This seems ok since we know which arguments were used when creating instance of |
Fixes #14832, fixes #13966, fixes #14622.
Still does not report error in #14777, I'll work separately on that.
Move all
ParamSpec
validity checking totypeanal.py
. Stop treatingP.args
andP.kwargs
as binding - only bare typevar makes it available in scope. Reject keyword arguments followingP.args
.This also makes one more conformance test pass. Diff (against baseline on current master):