bpo-29262: Add get_origin() and get_args() introspection helpers to typing (GH-13685)

This is an old feature request that appears from time to time. After a year of experimenting with various introspection capabilities in `typing_inspect` on PyPI, I propose to add these two most commonly used functions: `get_origin()` and `get_args()`. These are essentially thin public wrappers around private APIs: `__origin__` and `__args__`.

As discussed in the issue and on the typing tracker, exposing some public helpers instead of `__origin__` and `__args__` directly will give us more flexibility if we will decide to update the internal representation, while still maintaining backwards compatibility.

The implementation is very simple an is essentially a copy from `typing_inspect` with one exception: `ClassVar` was special-cased in `typing_inspect`, but I think this special-casing doesn't really help and only makes things more complicated.
This commit is contained in:
Ivan Levkivskyi 2019-05-31 00:10:07 +01:00 committed by GitHub
parent 2a58b0636d
commit 4c23aff065
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 99 additions and 0 deletions

View file

@ -15,6 +15,7 @@ from typing import Callable
from typing import Generic, ClassVar, Final, final, Protocol
from typing import cast, runtime_checkable
from typing import get_type_hints
from typing import get_origin, get_args
from typing import no_type_check, no_type_check_decorator
from typing import Type
from typing import NewType
@ -2735,6 +2736,42 @@ class GetTypeHintTests(BaseTestCase):
self.assertEqual(gth(G), {'lst': ClassVar[List[T]]})
class GetUtilitiesTestCase(TestCase):
def test_get_origin(self):
T = TypeVar('T')
class C(Generic[T]): pass
self.assertIs(get_origin(C[int]), C)
self.assertIs(get_origin(C[T]), C)
self.assertIs(get_origin(int), None)
self.assertIs(get_origin(ClassVar[int]), ClassVar)
self.assertIs(get_origin(Union[int, str]), Union)
self.assertIs(get_origin(Literal[42, 43]), Literal)
self.assertIs(get_origin(Final[List[int]]), Final)
self.assertIs(get_origin(Generic), Generic)
self.assertIs(get_origin(Generic[T]), Generic)
self.assertIs(get_origin(List[Tuple[T, T]][int]), list)
def test_get_args(self):
T = TypeVar('T')
class C(Generic[T]): pass
self.assertEqual(get_args(C[int]), (int,))
self.assertEqual(get_args(C[T]), (T,))
self.assertEqual(get_args(int), ())
self.assertEqual(get_args(ClassVar[int]), (int,))
self.assertEqual(get_args(Union[int, str]), (int, str))
self.assertEqual(get_args(Literal[42, 43]), (42, 43))
self.assertEqual(get_args(Final[List[int]]), (List[int],))
self.assertEqual(get_args(Union[int, Tuple[T, int]][str]),
(int, Tuple[str, int]))
self.assertEqual(get_args(typing.Dict[int, Tuple[T, T]][Optional[int]]),
(int, Tuple[Optional[int], Optional[int]]))
self.assertEqual(get_args(Callable[[], T][int]), ([], int,))
self.assertEqual(get_args(Union[int, Callable[[Tuple[T, ...]], str]]),
(int, Callable[[Tuple[T, ...]], str]))
self.assertEqual(get_args(Tuple[int, ...]), (int, ...))
self.assertEqual(get_args(Tuple[()]), ((),))
class CollectionsAbcTests(BaseTestCase):
def test_hashable(self):