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

PEP 646 implementation #963

Merged
merged 27 commits into from
Feb 12, 2022
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c8463e8
all the tests pass
JelleZijlstra Nov 24, 2021
7fcea86
lint fixes
JelleZijlstra Nov 24, 2021
be56a0a
more lint
JelleZijlstra Nov 24, 2021
c6d8747
fix 3.10
JelleZijlstra Nov 24, 2021
6deaf4c
separate Unpack tests
JelleZijlstra Dec 1, 2021
19233f7
update README
JelleZijlstra Dec 1, 2021
c241435
add get_origin/get_args tests
JelleZijlstra Dec 1, 2021
b2c7a5e
fix lint
JelleZijlstra Dec 1, 2021
c7d8823
fix name
JelleZijlstra Dec 1, 2021
8610e35
fix 3.6
JelleZijlstra Dec 1, 2021
9e820f4
that was not 3.6
JelleZijlstra Dec 1, 2021
f2cf02e
more thorough monkeypatching
JelleZijlstra Dec 1, 2021
0f386e2
fix lint
JelleZijlstra Dec 1, 2021
55c4d20
3.6 hacks
JelleZijlstra Dec 1, 2021
9229373
give up on 3.6
JelleZijlstra Jan 15, 2022
0d16423
docs
JelleZijlstra Jan 15, 2022
ff2f05c
TypeVarTuple docstring (adapted from the PEP)
JelleZijlstra Jan 15, 2022
e4cac11
Merge branch 'master' into pep646
JelleZijlstra Jan 15, 2022
53219df
Merge branch 'master' into pep646
JelleZijlstra Jan 15, 2022
d6d5ba8
Merge branch 'master' into pep646
JelleZijlstra Jan 23, 2022
8ca9ed3
Merge branch 'master' into pep646
JelleZijlstra Jan 25, 2022
d3f77c2
improve tests, docs, parens
JelleZijlstra Feb 2, 2022
fdfe563
Merge branch 'master' into pep646
JelleZijlstra Feb 3, 2022
80d8477
Merge branch 'master' into pep646
JelleZijlstra Feb 9, 2022
e46a306
Merge branch 'master' into pep646
JelleZijlstra Feb 11, 2022
5cd13f6
Remove bound and variance from TypeVarTuple
JelleZijlstra Feb 11, 2022
22b9c18
Merge branch 'master' into pep646
JelleZijlstra Feb 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions typing_extensions/CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Release 4.x.x

- Runtime support for PEP 646, adding `typing_extensions.TypeVarTuple`
and `typing_extensions.Unpack`.
- Runtime support for PEP 675 and `typing_extensions.LiteralString`.
- Add `Never` and `assert_never`. Backport from bpo-46475.
- `ParamSpec` args and kwargs are now equal to themselves. Backport from
Expand Down
14 changes: 11 additions & 3 deletions typing_extensions/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ This module currently contains the following:
- ``Never``
- ``reveal_type``
- ``Self`` (see PEP 673)
- ``TypeVarTuple`` (see PEP 646)
- ``Unpack`` (see PEP 646)

- In ``typing`` since Python 3.10

Expand Down Expand Up @@ -124,9 +126,15 @@ These changes are _not_ backported to prevent subtle compatibility
issues when mixing the differing implementations of modified classes.

Certain types have incorrect runtime behavior due to limitations of older
versions of the typing module. For example, ``ParamSpec`` and ``Concatenate``
will not work with ``get_args``, ``get_origin``. Certain PEP 612 special cases
in user-defined ``Generic``\ s are also not available.
versions of the typing module:

- ``ParamSpec`` and ``Concatenate`` will not work with ``get_args`` and
``get_origin``. Certain PEP 612 special cases in user-defined
``Generic``\ s are also not available.
- ``Unpack`` from PEP 646 does not work properly with user-defined
Copy link
Member

@Fidget-Spinner Fidget-Spinner Feb 1, 2022

Choose a reason for hiding this comment

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

To clarify, this means even with our monkey patching, subscripting with arbitrary number of type arguments won't work right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Defining the class doesn't even work. I'll make the note more precise.

Python 3.6.10 (default, Apr 28 2021, 18:14:25) 
[GCC Apple LLVM 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from typing import Generic
>>> from typing_extensions import Unpack, TypeVarTuple
>>> Ts = TypeVarTuple("Ts")
>>> class X(Generic[Unpack[Ts]]): pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/jelle/.pyenv/versions/3.6.10/lib/python3.6/typing.py", line 965, in __new__
    ", ".join(str(g) for g in gvars)))
TypeError: Some type variables (Ts) are not listed in Generic[typing_extensions.Unpack[Ts]]

``Generic``\ s in Python 3.6: ``class X(Generic[Unpack[Ts]]):`` does
not work.

These types are only guaranteed to work for static type checking.

Running tests
Expand Down
147 changes: 146 additions & 1 deletion typing_extensions/src/test_typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from typing_extensions import TypeAlias, ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs, TypeGuard
from typing_extensions import Awaitable, AsyncIterator, AsyncContextManager, Required, NotRequired
from typing_extensions import Protocol, runtime, runtime_checkable, Annotated, overload, final, is_typeddict
from typing_extensions import dataclass_transform, reveal_type, Never, assert_never, LiteralString
from typing_extensions import TypeVarTuple, Unpack, dataclass_transform, reveal_type, Never, assert_never, LiteralString
try:
from typing_extensions import get_type_hints
except ImportError:
Expand Down Expand Up @@ -610,6 +610,7 @@ def test_get_origin(self):

T = TypeVar('T')
P = ParamSpec('P')
Ts = TypeVarTuple('Ts')
class C(Generic[T]): pass
self.assertIs(get_origin(C[int]), C)
self.assertIs(get_origin(C[T]), C)
Expand All @@ -630,11 +631,16 @@ class C(Generic[T]): pass
self.assertIs(get_origin(list), None)
self.assertIs(get_origin(P.args), P)
self.assertIs(get_origin(P.kwargs), P)
self.assertIs(get_origin(Required[int]), Required)
self.assertIs(get_origin(NotRequired[int]), NotRequired)
self.assertIs(get_origin(Unpack[Ts]), Unpack)
self.assertIs(get_origin(Unpack), None)

def test_get_args(self):
from typing_extensions import get_args

T = TypeVar('T')
Ts = TypeVarTuple('Ts')
class C(Generic[T]): pass
self.assertEqual(get_args(C[int]), (int,))
self.assertEqual(get_args(C[T]), (T,))
Expand Down Expand Up @@ -675,6 +681,10 @@ class C(Generic[T]): pass
self.assertIn(get_args(Callable[P, int]), [(P, int), ([P], int)])
self.assertEqual(get_args(Callable[Concatenate[int, P], int]),
(Concatenate[int, P], int))
self.assertEqual(get_args(Required[int]), (int,))
self.assertEqual(get_args(NotRequired[int]), (int,))
self.assertEqual(get_args(Unpack[Ts]), (Ts,))
self.assertEqual(get_args(Unpack), ())


class CollectionsAbcTests(BaseTestCase):
Expand Down Expand Up @@ -2404,6 +2414,141 @@ def test_pickle(self):
self.assertIs(Self, pickle.loads(pickled))


class UnpackTests(BaseTestCase):
def test_basic_plain(self):
Ts = TypeVarTuple('Ts')
self.assertEqual(Unpack[Ts], Unpack[Ts])
with self.assertRaises(TypeError):
Unpack()

def test_repr(self):
Ts = TypeVarTuple('Ts')
self.assertEqual(repr(Unpack[Ts]), 'typing_extensions.Unpack[Ts]')

def test_cannot_subclass_vars(self):
with self.assertRaises(TypeError):
class V(Unpack[TypeVarTuple('Ts')]):
pass

def test_tuple(self):
Ts = TypeVarTuple('Ts')
Tuple[Unpack[Ts]]

def test_union(self):
Xs = TypeVarTuple('Xs')
Ys = TypeVarTuple('Ys')
self.assertEqual(
Union[Unpack[Xs]],
Unpack[Xs]
)
self.assertNotEqual(
Union[Unpack[Xs]],
Union[Unpack[Xs], Unpack[Ys]]
)
self.assertEqual(
Union[Unpack[Xs], Unpack[Xs]],
Unpack[Xs]
)
self.assertNotEqual(
Union[Unpack[Xs], int],
Union[Unpack[Xs]]
)
self.assertNotEqual(
Union[Unpack[Xs], int],
Union[int]
)
self.assertEqual(
Union[Unpack[Xs], int].__args__,
(Unpack[Xs], int)
)
self.assertEqual(
Union[Unpack[Xs], int].__parameters__,
(Xs,)
)
self.assertIs(
Union[Unpack[Xs], int].__origin__,
Union
)

@skipUnless(PEP_560, "Unimplemented for 3.6")
def test_concatenation(self):
Xs = TypeVarTuple('Xs')
self.assertEqual(Tuple[int, Unpack[Xs]].__args__, (int, Unpack[Xs]))
self.assertEqual(Tuple[Unpack[Xs], int].__args__, (Unpack[Xs], int))
self.assertEqual(Tuple[int, Unpack[Xs], str].__args__,
(int, Unpack[Xs], str))
class C(Generic[Unpack[Xs]]): pass
self.assertEqual(C[int, Unpack[Xs]].__args__, (int, Unpack[Xs]))
self.assertEqual(C[Unpack[Xs], int].__args__, (Unpack[Xs], int))
self.assertEqual(C[int, Unpack[Xs], str].__args__,
(int, Unpack[Xs], str))

@skipUnless(PEP_560, "Unimplemented for 3.6")
def test_class(self):
Ts = TypeVarTuple('Ts')

class C(Generic[Unpack[Ts]]): pass
self.assertEqual(C[int].__args__, (int,))
self.assertEqual(C[int, str].__args__, (int, str))

with self.assertRaises(TypeError):
class C(Generic[Unpack[Ts], int]): pass

T1 = TypeVar('T')
T2 = TypeVar('T')
class C(Generic[T1, T2, Unpack[Ts]]): pass
self.assertEqual(C[int, str].__args__, (int, str))
self.assertEqual(C[int, str, float].__args__, (int, str, float))
self.assertEqual(C[int, str, float, bool].__args__, (int, str, float, bool))
with self.assertRaises(TypeError):
C[int]


class TypeVarTupleTests(BaseTestCase):

def test_basic_plain(self):
Ts = TypeVarTuple('Ts')
self.assertEqual(Ts, Ts)
self.assertIsInstance(Ts, TypeVarTuple)
Xs = TypeVarTuple('Xs')
Ys = TypeVarTuple('Ys')
self.assertNotEqual(Xs, Ys)

def test_repr(self):
Ts = TypeVarTuple('Ts')
self.assertEqual(repr(Ts), 'Ts')

def test_no_redefinition(self):
self.assertNotEqual(TypeVarTuple('Ts'), TypeVarTuple('Ts'))

def test_cannot_subclass_vars(self):
with self.assertRaises(TypeError):
class V(TypeVarTuple('Ts')):
pass

def test_cannot_subclass_var_itself(self):
with self.assertRaises(TypeError):
class V(TypeVarTuple):
pass

def test_cannot_instantiate_vars(self):
Ts = TypeVarTuple('Ts')
with self.assertRaises(TypeError):
Ts()

def test_tuple(self):
Ts = TypeVarTuple('Ts')
# Not legal at type checking time but we can't really check against it.
Tuple[Ts]

def test_args_and_parameters(self):
Ts = TypeVarTuple('Ts')

t = Tuple[tuple(Ts)]
self.assertEqual(t.__args__, (Ts.__unpacked__,))
self.assertEqual(t.__parameters__, (Ts,))


class FinalDecoratorTests(BaseTestCase):
def test_final_unmodified(self):
def func(x): ...
Expand Down
Loading