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

Don't turn list defaults for ParamSpecs into tuples #394

Merged
merged 2 commits into from
May 16, 2024

Conversation

AlexWaygood
Copy link
Member

PEP 696 specifies that default values for ParamSpecs must be lists, and CPython on 3.13 keeps them as a list for the __default__ attribute:

Python 3.14.0a0 (heads/cleanup-typing:2e98d5dbf9, May 11 2024, 12:20:48) [Clang 15.0.0 (clang-1500.3.9.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def foo[**P = [str, int]](): pass
... 
>>> foo.__type_params__[0].__default__
[<class 'str'>, <class 'int'>]
>>> 

Currently in the typing_extensions version, however, we turn any list into a tuple, which seems wrong:

(main) % python                                                                                                          ~/dev/typing_extensions/src
Python 3.12.3 (main, Apr 30 2024, 10:12:02) [Clang 15.0.0 (clang-1500.3.9.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from typing_extensions import ParamSpec
>>> ParamSpec("P", default=[int, str]).__default__
(<class 'int'>, <class 'str'>)

This PR fixes that.

Comment on lines 1471 to 1473
type_param.__default__ = type(default)(
typing._type_check(d, "Default must be a type") for d in default
)
Copy link
Member Author

@AlexWaygood AlexWaygood May 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _type_check() calls here feel "morally correct" in a sense -- they're consistent with what a lot of the rest of the typing.py internals do. But on the other hand, CPython doesn't actually do any check at all in its 3.13 implementation; it just sets the __default__ attribute to the value passed in, and moves on.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So maybe we should just do that here too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure whether the bug was that we were being too lenient or that CPython wasn't being restrictive enough. But having slept on it, I now agree that we should just accept any default value, and not do any type checking here. That's consistent with what CPython has always done for TypeVar bounds and TypeVar constraints, which should also conceptually be types:

% pyenv local 3.11                                                                                                % python
Python 3.11.8 (main, Feb 15 2024, 19:32:18) [Clang 15.0.0 (clang-1500.1.0.2.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from typing import TypeVar
>>> def not_a_type(): pass
... 
>>> T = TypeVar("T", bound=not_a_type)
>>> U = TypeVar("U", not_a_type, not_a_type)

src/test_typing_extensions.py Show resolved Hide resolved
Comment on lines 1471 to 1473
type_param.__default__ = type(default)(
typing._type_check(d, "Default must be a type") for d in default
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So maybe we should just do that here too?

@AlexWaygood AlexWaygood merged commit 23378be into main May 16, 2024
18 checks passed
@AlexWaygood AlexWaygood deleted the list-to-tuple-bug branch May 16, 2024 11:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants