You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Typing: improve error messages for invalid ParamSpec substitutions #102725
PEP-612 is a complex typing PEP that introduced some complex rules, both for static type checkers and for CPython at runtime. It can be hard to remember the intricacies of all these rules -- both for users and for typing maintainers.
One thing that might help here is if we had better error messages in situations where the runtime raises exceptions. For example, in the following snippet, the runtime is arguably correct in raising TypeErrors -- by the rules laid out in PEP-612, both of these are invalid substitutions for two reasons:
Parameters can only be prepended to a ParamSpec in a parameters list using typing(_extensions).Concatenate.
Appending parameters to a ParamSpec in a parameters list is disallowed.
However, the error messages don't mention either of these things, and are in fact pretty baffling:
Running PGUpdate|x64 interpreter...
Python 3.12.0a6+ (heads/main:12226bec25, Mar 10 2023, 17:32:23) [MSC v.1932 64 bit (AMD64)] on win32
>>> import typing as t, collections.abc as c
>>> P, T = t.ParamSpec("P"), t.TypeVar("T")
>>> c.Callable[P, T][[P, str], bool][int]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<frozen _collections_abc>", line 501, in __getitem__
File "<frozen _collections_abc>", line 456, in __new__
TypeError: Callable must be used as Callable[[arg, ...], result].
>>> classMyCallable(t.Generic[P, T]): ...
...
>>> MyCallable[P, T][[P, str], bool][int]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\alexw\coding\cpython\Lib\typing.py", line 354, in inner
return func(*args, **kwds)
^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\cpython\Lib\typing.py", line 1403, in __getitem__
raise TypeError(f"{self} is not a generic class")
TypeError: __main__.MyCallable[[~P, str], bool] is not a generic class
Previous discussion
This issue is a followup to some points raised in:
Should we fix it? It will require quite a bit of work to get all the things right.
I can do it if we need it. Or we can keep this up to a user to control.
If it can be fixed without excessively complicating the code of typing.py, and if we can be 100% sure that we're not introducing false-positive errors, then I'll be happy to review a PR. But our general position is that it's better for the runtime to err on the side of leniency, and leave it to type checkers to point out invalid uses of typing constructs. We've had lots of situations in the past where strict checks at runtime have made typing_extensions backports complicated, or interfered with people using type annotations in unusual/experimental ways. Therefore, I view these "false negatives" at runtime as being quite low-priority concerns.
main.py:6: error: Invalid location for ParamSpec "P" [valid-type]
main.py:6: note: You can use ParamSpec as the first argument to Callable, e.g., 'Callable[P, int]'
Synchronizing them will be a huge pain.
Because the exception happens on [int] substitution. But, we have to make an invalid substitution here c.Callable[P, T][[P, str], bool] to be able to reach this state.
So, I think we should just close this issue.
There's nothing that can be easily done to solve a hypothetical issue.
Activity
sobolevn commentedon Apr 11, 2023
Update: turns out the later substitution does not raise an error anymore on
main:Not good!
I think that this error is helpful and should be restored with a better message.
sobolevn commentedon Apr 11, 2023
We can now even substitute
Twith[P, int]:Not good at all!
sobolevn commentedon Apr 11, 2023
Should we fix it? It will require quite a bit of work to get all the things right.
I can do it if we need it. Or we can keep this up to a user to control.
AlexWaygood commentedon Apr 11, 2023
If it can be fixed without excessively complicating the code of
typing.py, and if we can be 100% sure that we're not introducing false-positive errors, then I'll be happy to review a PR. But our general position is that it's better for the runtime to err on the side of leniency, and leave it to type checkers to point out invalid uses oftypingconstructs. We've had lots of situations in the past where strict checks at runtime have madetyping_extensionsbackports complicated, or interfered with people using type annotations in unusual/experimental ways. Therefore, I view these "false negatives" at runtime as being quite low-priority concerns.sobolevn commentedon Apr 11, 2023
Let's start with the second example.
The change itself is quite easy:
But, it has several flaws.
collections.abc.Callabledoes not do the sameSo, I think we should leave this as-is.
Now, let's get back to your first example.
It is also problematic, because right now
typing.Callabledoes not produce this error:Synchronizing them will be a huge pain.
Because the exception happens on
[int]substitution. But, we have to make an invalid substitution herec.Callable[P, T][[P, str], bool]to be able to reach this state.So, I think we should just close this issue.
There's nothing that can be easily done to solve a hypothetical issue.