|
7 | 7 | import subprocess |
8 | 8 | import types |
9 | 9 | from unittest import TestCase, main, skipUnless, skipIf |
10 | | -from typing import TypeVar, Optional |
| 10 | +from typing import TypeVar, Optional, Union |
11 | 11 | from typing import T, KT, VT # Not in __all__. |
12 | | -from typing import Tuple, List, Dict, Iterator |
| 12 | +from typing import Tuple, List, Dict, Iterator, Callable |
13 | 13 | from typing import Generic |
14 | 14 | from typing import no_type_check |
15 | 15 | from typing_extensions import NoReturn, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict |
16 | | -from typing_extensions import TypeAlias, ParamSpec, Concatenate |
| 16 | +from typing_extensions import TypeAlias, ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs |
17 | 17 |
|
18 | 18 | try: |
19 | 19 | from typing_extensions import Protocol, runtime, runtime_checkable |
@@ -519,6 +519,80 @@ def test_final_forward_ref(self): |
519 | 519 | self.assertNotEqual(gth(Loop, globals())['attr'], Final) |
520 | 520 |
|
521 | 521 |
|
| 522 | +@skipUnless(PEP_560, "Python 3.7+ required") |
| 523 | +class GetUtilitiesTestCase(TestCase): |
| 524 | + def test_get_origin(self): |
| 525 | + from typing_extensions import get_origin |
| 526 | + |
| 527 | + T = TypeVar('T') |
| 528 | + P = ParamSpec('P') |
| 529 | + class C(Generic[T]): pass |
| 530 | + self.assertIs(get_origin(C[int]), C) |
| 531 | + self.assertIs(get_origin(C[T]), C) |
| 532 | + self.assertIs(get_origin(int), None) |
| 533 | + self.assertIs(get_origin(ClassVar[int]), ClassVar) |
| 534 | + self.assertIs(get_origin(Union[int, str]), Union) |
| 535 | + self.assertIs(get_origin(Literal[42, 43]), Literal) |
| 536 | + self.assertIs(get_origin(Final[List[int]]), Final) |
| 537 | + self.assertIs(get_origin(Generic), Generic) |
| 538 | + self.assertIs(get_origin(Generic[T]), Generic) |
| 539 | + self.assertIs(get_origin(List[Tuple[T, T]][int]), list) |
| 540 | + self.assertIs(get_origin(Annotated[T, 'thing']), Annotated) |
| 541 | + self.assertIs(get_origin(List), list) |
| 542 | + self.assertIs(get_origin(Tuple), tuple) |
| 543 | + self.assertIs(get_origin(Callable), collections.abc.Callable) |
| 544 | + if sys.version_info >= (3, 9): |
| 545 | + self.assertIs(get_origin(list[int]), list) |
| 546 | + self.assertIs(get_origin(list), None) |
| 547 | + self.assertIs(get_origin(P.args), P) |
| 548 | + self.assertIs(get_origin(P.kwargs), P) |
| 549 | + |
| 550 | + def test_get_args(self): |
| 551 | + from typing_extensions import get_args |
| 552 | + |
| 553 | + T = TypeVar('T') |
| 554 | + class C(Generic[T]): pass |
| 555 | + self.assertEqual(get_args(C[int]), (int,)) |
| 556 | + self.assertEqual(get_args(C[T]), (T,)) |
| 557 | + self.assertEqual(get_args(int), ()) |
| 558 | + self.assertEqual(get_args(ClassVar[int]), (int,)) |
| 559 | + self.assertEqual(get_args(Union[int, str]), (int, str)) |
| 560 | + self.assertEqual(get_args(Literal[42, 43]), (42, 43)) |
| 561 | + self.assertEqual(get_args(Final[List[int]]), (List[int],)) |
| 562 | + self.assertEqual(get_args(Union[int, Tuple[T, int]][str]), |
| 563 | + (int, Tuple[str, int])) |
| 564 | + self.assertEqual(get_args(typing.Dict[int, Tuple[T, T]][Optional[int]]), |
| 565 | + (int, Tuple[Optional[int], Optional[int]])) |
| 566 | + self.assertEqual(get_args(Callable[[], T][int]), ([], int)) |
| 567 | + self.assertEqual(get_args(Callable[..., int]), (..., int)) |
| 568 | + self.assertEqual(get_args(Union[int, Callable[[Tuple[T, ...]], str]]), |
| 569 | + (int, Callable[[Tuple[T, ...]], str])) |
| 570 | + self.assertEqual(get_args(Tuple[int, ...]), (int, ...)) |
| 571 | + self.assertEqual(get_args(Tuple[()]), ((),)) |
| 572 | + self.assertEqual(get_args(Annotated[T, 'one', 2, ['three']]), (T, 'one', 2, ['three'])) |
| 573 | + self.assertEqual(get_args(List), ()) |
| 574 | + self.assertEqual(get_args(Tuple), ()) |
| 575 | + self.assertEqual(get_args(Callable), ()) |
| 576 | + if sys.version_info >= (3, 9): |
| 577 | + self.assertEqual(get_args(list[int]), (int,)) |
| 578 | + self.assertEqual(get_args(list), ()) |
| 579 | + if sys.version_info >= (3, 9): |
| 580 | + # Support Python versions with and without the fix for |
| 581 | + # https://bugs.python.org/issue42195 |
| 582 | + # The first variant is for 3.9.2+, the second for 3.9.0 and 1 |
| 583 | + self.assertIn(get_args(collections.abc.Callable[[int], str]), |
| 584 | + (([int], str), ([[int]], str))) |
| 585 | + self.assertIn(get_args(collections.abc.Callable[[], str]), |
| 586 | + (([], str), ([[]], str))) |
| 587 | + self.assertEqual(get_args(collections.abc.Callable[..., str]), (..., str)) |
| 588 | + P = ParamSpec('P') |
| 589 | + # In 3.9 and lower we use typing_extensions's hacky implementation |
| 590 | + # of ParamSpec, which gets incorrectly wrapped in a list |
| 591 | + self.assertIn(get_args(Callable[P, int]), [(P, int), ([P], int)]) |
| 592 | + self.assertEqual(get_args(Callable[Concatenate[int, P], int]), |
| 593 | + (Concatenate[int, P], int)) |
| 594 | + |
| 595 | + |
522 | 596 | class CollectionsAbcTests(BaseTestCase): |
523 | 597 |
|
524 | 598 | def test_isinstance_collections(self): |
@@ -1952,8 +2026,17 @@ def test_valid_uses(self): |
1952 | 2026 | # ParamSpec instances should also have args and kwargs attributes. |
1953 | 2027 | self.assertIn('args', dir(P)) |
1954 | 2028 | self.assertIn('kwargs', dir(P)) |
1955 | | - P.args |
1956 | | - P.kwargs |
| 2029 | + |
| 2030 | + def test_args_kwargs(self): |
| 2031 | + P = ParamSpec('P') |
| 2032 | + self.assertIn('args', dir(P)) |
| 2033 | + self.assertIn('kwargs', dir(P)) |
| 2034 | + self.assertIsInstance(P.args, ParamSpecArgs) |
| 2035 | + self.assertIsInstance(P.kwargs, ParamSpecKwargs) |
| 2036 | + self.assertIs(P.args.__origin__, P) |
| 2037 | + self.assertIs(P.kwargs.__origin__, P) |
| 2038 | + self.assertEqual(repr(P.args), "P.args") |
| 2039 | + self.assertEqual(repr(P.kwargs), "P.kwargs") |
1957 | 2040 |
|
1958 | 2041 | # Note: ParamSpec doesn't work for pre-3.10 user-defined Generics due |
1959 | 2042 | # to type checks inside Generic. |
@@ -2072,7 +2155,7 @@ def test_typing_extensions_defers_when_possible(self): |
2072 | 2155 | 'Final', |
2073 | 2156 | 'get_type_hints' |
2074 | 2157 | } |
2075 | | - if sys.version_info[:2] == (3, 8): |
| 2158 | + if sys.version_info < (3, 10): |
2076 | 2159 | exclude |= {'get_args', 'get_origin'} |
2077 | 2160 | for item in typing_extensions.__all__: |
2078 | 2161 | if item not in exclude and hasattr(typing, item): |
|
0 commit comments