8000 Expose TypeVar and friends through _typing · python/cpython@e0a0b04 · GitHub
[go: up one dir, main page]

Skip to content

Commit e0a0b04

Browse files
committed
Expose TypeVar and friends through _typing
1 parent e65d668 commit e0a0b04

File tree

3 files changed

+54
-76
lines changed

3 files changed

+54
-76
lines changed

Lib/test/test_typing.py

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,6 @@
4848
from test import _typed_dict_helper
4949

5050

51-
py_typing = import_helper.import_fresh_module('typing', blocked=['_typing'])
52-
c_typing = import_helper.import_fresh_module('typing', fresh=['_typing'])
53-
54-
5551
CANNOT_SUBCLASS_TYPE = 'Cannot subclass special typing classes'
5652
NOT_A_BASE_TYPE = "type 'typing.%s' is not an acceptable base type"
5753
CANNOT_SUBCLASS_INSTANCE = 'Cannot subclass an instance of %s'
@@ -6434,34 +6430,27 @@ def foo(a: A) -> Optional[BaseException]:
64346430
class TestModules(TestCase):
64356431
func_names = ['_idfunc']
64366432

6437-
def test_py_functions(self):
6438-
for fname in self.func_names:
6439-
self.assertEqual(getattr(py_typing, fname).__module__, 'typing')
6440-
6441-
@skipUnless(c_typing, 'requires _typing')
64426433
def test_c_functions(self):
64436434
for fname in self.func_names:
6444-
self.assertEqual(getattr(c_typing, fname).__module__, '_typing')
6435+
self.assertEqual(getattr(typing, fname).__module__, '_typing')
64456436

64466437

6447-
class NewTypeTests:
6438+
class NewTypeTests(BaseTestCase):
64486439
def cleanup(self):
6449-
for f in self.module._cleanups:
6440+
for f in typing._cleanups:
64506441
f()
64516442

64526443
@classmethod
64536444
def setUpClass(cls):
6454-
sys.modules['typing'] = cls.module
64556445
global UserId
6456-
UserId = cls.module.NewType('UserId', int)
6457-
cls.UserName = cls.module.NewType(cls.__qualname__ + '.UserName', str)
6446+
UserId = typing.NewType('UserId', int)
6447+
cls.UserName = typing.NewType(cls.__qualname__ + '.UserName', str)
64586448

64596449
@classmethod
64606450
def tearDownClass(cls):
64616451
global UserId
64626452
del UserId
64636453
del cls.UserName
6464-
sys.modules['typing'] = typing
64656454

64666455
def tearDown(self):
64676456
self.cleanup()
@@ -6481,11 +6470,11 @@ class D(UserId):
64816470
def test_or(self):
64826471
for cls in (int, self.UserName):
64836472
with self.subTest(cls=cls):
6484-
self.assertEqual(UserId | cls, self.module.Union[UserId, cls])
6485-
self.assertEqual(cls | UserId, self.module.Union[cls, UserId])
6473+
self.assertEqual(UserId | cls, typing.Union[UserId, cls])
6474+
self.assertEqual(cls | UserId, typing.Union[cls, UserId])
64866475

6487-
self.assertEqual(self.module.get_args(UserId | cls), (UserId, cls))
6488-
self.assertEqual(self.module.get_args(cls | UserId), (cls, UserId))
6476+
self.assertEqual(typing.get_args(UserId | cls), (UserId, cls))
6477+
self.assertEqual(typing.get_args(cls | UserId), (cls, UserId))
64896478

64906479
def test_special_attrs(self):
64916480
self.assertEqual(UserId.__name__, 'UserId')
@@ -6506,7 +6495,7 @@ def test_repr(self):
65066495
f'{__name__}.{self.__class__.__qualname__}.UserName')
65076496

65086497
def test_pickle(self):
6509-
UserAge = self.module.NewType('UserAge', float)
6498+
UserAge = typing.NewType('UserAge', float)
65106499
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
65116500
with self.subTest(proto=proto):
65126501
pickled = pickle.dumps(UserId, proto)
@@ -6538,15 +6527,6 @@ class ProUserId(UserId):
65386527
...
65396528

65406529

6541-
class NewTypePythonTests(NewTypeTests, BaseTestCase):
6542-
module = py_typing
6543-
6544-
6545-
@skipUnless(c_typing, 'requires _typing')
6546-
class NewTypeCTests(NewTypeTests, BaseTestCase):
6547-
module = c_typing
6548-
6549-
65506530
class NamedTupleTests(BaseTestCase):
65516531
class NestedEmployee(NamedTuple):
65526532
name: str

Lib/typing.py

Lines changed: 18 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,16 @@
3333
import warnings
3434
from types import WrapperDescriptorType, MethodWrapperType, MethodDescriptorType, GenericAlias
3535

36-
37-
try:
38-
from _typing import _idfunc
39-
except ImportError:
40-
def _idfunc(_, x):
41-
return x
36+
from _typing import (
37+
_idfunc,
38+
TypeVar,
39+
ParamSpec,
40+
TypeVarTuple,
41+
ParamSpecArgs,
42+
ParamSpecKwargs,
43+
TypeAliasType,
44+
Generic,
45+
)
4246

4347
# Please keep __all__ alphabetized within each category.
4448
__all__ = [
@@ -180,11 +184,7 @@ def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms=
180184
181185
We append the repr() of the actual value (truncated to 100 chars).
182186
"""
183-
try:
184-
invalid_generic_forms = (Generic, Protocol)
185-
except NameError:
186-
# Run during interpreter startup
187-
return arg
187+
invalid_generic_forms = (Generic, Protocol)
188188
if not allow_special_forms:
189189
invalid_generic_forms += (ClassVar,)
190190
if is_argument:
@@ -1022,11 +1022,7 @@ def _generic_class_getitem(cls, params):
10221022
params = (params,)
10231023

10241024
params = tuple(_type_convert(p) for p in params)
1025-
try:
1026-
is_generic_or_protocol = cls in (Generic, Protocol)
1027-
except NameError:
1028-
# Happens during interpreter startup
1029-
return _GenericAlias(cls, params, _paramspec_tvars=True)
1025+
is_generic_or_protocol = cls in (Generic, Protocol)
10301026

10311027
if is_generic_or_protocol:
10321028
# Generic and Protocol can only be subscripted with unique type variables.
@@ -1062,18 +1058,12 @@ def _generic_class_getitem(cls, params):
10621058

10631059

10641060
def _generic_init_subclass(cls, *args, **kwargs):
1065-
try:
1066-
generic_cls = Generic
1067-
except NameError:
1068-
# Happens during interpreter startup. We are creating
1069-
# the _Dummy class.
1070-
generic_cls = cls.__mro__[1]
1071-
super(generic_cls, cls).__init_subclass__(*args, **kwargs)
1061+
super(Generic, cls).__init_subclass__(*args, **kwargs)
10721062
tvars = []
10731063
if '__orig_bases__' in cls.__dict__:
1074-
error = generic_cls in cls.__orig_bases__
1064+
error = Generic in cls.__orig_bases__
10751065
else:
1076-
error = (generic_cls in cls.__bases__ and
1066+
error = (Generic in cls.__bases__ and
10771067
cls.__name__ != 'Protocol' and
10781068
type(cls) != _TypedDictMeta)
10791069
if error:
@@ -1088,7 +1078,7 @@ def _generic_init_subclass(cls, *args, **kwargs):
10881078
gvars = None
10891079
for base in cls.__orig_bases__:
10901080
if (isinstance(base, _GenericAlias) and
1091-
base.__origin__ is generic_cls):
1081+
base.__origin__ is Generic):
10921082
if gvars is not None:
10931083
raise TypeError(
10941084
"Cannot inherit from Generic[...] multiple types.")
@@ -1394,12 +1384,7 @@ def __mro_entries__(self, bases):
13941384

13951385
if self._name: # generic version of an ABC or built-in class
13961386
return super().__mro_entries__(bases)
1397-
try:
1398-
is_Generic = self.__origin__ is Generic
1399-
except NameError:
1400-
# Happens during interpreter startup
1401-
return (self.__origin__,)
1402-
if is_Generic:
1387+
if self.__origin__ is Generic:
14031388
if Protocol in bases:
14041389
return ()
14051390
i = bases.index(self)
@@ -1751,16 +1736,6 @@ def _lazy_load_getattr_static():
17511736

17521737
_cleanups.append(_lazy_load_getattr_static.cache_clear)
17531738

1754-
class _Dummy[T, *Ts, **P]:
1755-
pass
1756-
1757-
TypeVar = type(_Dummy.__type_params__[0])
1758-
TypeVarTuple = type(_Dummy.__type_params__[1])
1759-
ParamSpec = type(_Dummy.__type_params__[2])
1760-
ParamSpecArgs = type(ParamSpec("P").args)
1761-
ParamSpecKwargs = type(ParamSpec("P").kwargs)
1762-
Generic = _Dummy.__mro__[1]
1763-
17641739
def _pickle_psargs(psargs):
17651740
return ParamSpecArgs, (psargs.__origin__,)
17661741

@@ -1771,10 +1746,7 @@ def _pickle_pskwargs(pskwargs):
17711746

17721747
copyreg.pickle(ParamSpecKwargs, _pickle_pskwargs)
17731748

1774-
type _Alias = int
1775-
TypeAliasType = type(_Alias)
1776-
1777-
del _Dummy, _pickle_psargs, _pickle_pskwargs, _Alias
1749+
del _pickle_psargs, _pickle_pskwargs
17781750

17791751

17801752
class _ProtocolMeta(ABCMeta):

Modules/_typingmodule.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
/* typing accelerator C extension: _typing module. */
22

3+
#define Py_BUILD_CORE
4+
35
#include "Python.h"
6+
#include "internal/pycore_interp.h"
47
#include "clinic/_typingmodule.c.h"
58

69
/*[clinic input]
@@ -35,7 +38,30 @@ static PyMethodDef typing_methods[] = {
3538
PyDoc_STRVAR(typing_doc,
3639
"Accelerators for the typing module.\n");
3740

41+
static int
42+
_typing_exec(PyObject *m)
43+
{
44+
PyInterpreterState *interp = PyInterpreterState_Get();
45+
46+
#define EXPORT_TYPE(name, typename) \
47+
if (PyModule_AddObjectRef(m, name, \
48+
(PyObject *)interp->cached_objects.typename) < 0) { \
49+
return -1; \
50+
}
51+
52+
EXPORT_TYPE("TypeVar", typevar_type);
53+
EXPORT_TYPE("TypeVarTuple", typevartuple_type);
54+
EXPORT_TYPE("ParamSpec", paramspec_type);
55+
EXPORT_TYPE("ParamSpecArgs", paramspecargs_type);
56+
EXPORT_TYPE("ParamSpecKwargs", paramspeckwargs_type);
57+
EXPORT_TYPE("TypeAliasType", typealias_type);
58+
EXPORT_TYPE("Generic", generic_type);
59+
#undef EXPORT_TYPE
60+
return 0;
61+
}
62+
3863
static struct PyModuleDef_Slot _typingmodule_slots[] = {
64+
{Py_mod_exec, _typing_exec},
3965
{0, NULL}
4066
};
4167

0 commit comments

Comments
 (0)
0