GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — bpo-44801: Check arguments in substitution of ParamSpec in Callable by serhiy-storchaka · Pull Request #27585 · python/cpython Conversation
|
| for arg in self.__args__: | ||
| if _is_typevarlike(arg): | ||
| arg = subst[arg] | ||
| if _is_param_expr(arg): |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Checking for something like _is_paramspec would be clearer IMO, but we don't have that function and it's kind of a waste to make a function just for this one-time use.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| C1 = Callable[P, T] | ||
| # substitution | ||
| self.assertEqual(C1[int, str], Callable[[int], str]) | ||
| self.assertEqual(C1[[int], str], Callable[[int], str]) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Hmm I feel a little strange about this. I feel that the new form is correct, but I also feel the old form should work. There's not much ambiguity in using the old form.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
The PEP explicitly claim that only substituting ParamSpec with the parameters expression should be accepted. It will also simplify the future code.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Ah ok I see it now:
def f(x: X[int, int]) -> str: ... # Rejected
Thanks for the reminder.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| self.assertEqual(C1[int, str], Callable[[int], str]) | ||
| self.assertEqual(C1[[int], str], Callable[[int], str]) | ||
| self.assertEqual(C1[[int, str], str], Callable[[int, str], str]) | ||
| self.assertEqual(C1[[], str], Callable[[], str]) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Good test! 👍
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| self.assertEqual(G5, G6) | ||
|
|
||
| G7 = Z[int] | ||
| self.assertEqual(G7.__args__, ((int,),)) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
This isn't a critique of your PR, but a minor regret of mine: Looking at G5, G6, G7, I realized their __args__ should be (int, str, bool) or (int, ), etc.; not nested tuple with types. Nested tuple makes repr weird, and also nested tuple means any nested TypeVar or ParamSpec won't appear in __parameters__ and so can't be substituted.
I don't remember what made me code it like that back then, but it could be me not wanting to make the _GenericAlias.__getitem__ code complicated just for ParamSpec.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
It does not work for user generics because they can have more than one ParamSpec. For example:
class X(Generic[P1, P2]): f: Callable[P1, int] g: Callable[P2, str] G1 = X[[int, str], [bytes]] G2 = X[int, [str, bytes]] assert G1.__args__ == ((int, str), (bytes,)) assert G2.__args__ == ((int,) (str, bytes))
If flatten arguments, __args__ of G1 and G2 would be the same ((int, str, bytes)). But they are clearly different types.
I'll add a special test for this.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Right, thanks for pointing that out! I forgot there was ambiguity with multiple ParamSpec. Hopefully some future PEP makes this clearer.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Again, LGTM. Thanks for patiently addressing my questions Serhiy :).
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Thanks @serhiy-storchaka for the PR, and @ambv for merging it 🌮🎉.. I'm working now to backport this PR to: 3.10. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
…ythonGH-27585) (cherry picked from commit 3875a69) Co-authored-by: Serhiy Storchaka <[email protected]>
|
GH-27598 is a backport of this pull request to the 3.10 branch. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
…H-27585) (cherry picked from commit 3875a69) Co-authored-by: Serhiy Storchaka <[email protected]>
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.