Skip to content

Commit 1755157

Browse files
AA-TurnerpicnixzZeroIntensity
authored
GH-118761: Expose more core interpreter types in _types (#132103)
Co-authored-by: Bénédikt Tran <[email protected]> Co-authored-by: Peter Bierma <[email protected]>
1 parent 92fb949 commit 1755157

File tree

3 files changed

+128
-63
lines changed

3 files changed

+128
-63
lines changed

Lib/test/test_types.py

+26
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
run_with_locale, cpython_only, no_rerun,
55
MISSING_C_DOCSTRINGS, EqualToForwardRef,
66
)
7+
from test.support.import_helper import import_fresh_module
8+
79
import collections.abc
810
from collections import namedtuple, UserDict
911
import copy
@@ -19,6 +21,8 @@
1921
import weakref
2022
import typing
2123

24+
c_types = import_fresh_module('types', fresh=['_types'])
25+
py_types = import_fresh_module('types', blocked=['_types'])
2226

2327
T = typing.TypeVar("T")
2428

@@ -34,6 +38,28 @@ def clear_typing_caches():
3438

3539
class TypesTests(unittest.TestCase):
3640

41+
def test_names(self):
42+
c_only_names = {'CapsuleType'}
43+
ignored = {'new_class', 'resolve_bases', 'prepare_class',
44+
'get_original_bases', 'DynamicClassAttribute', 'coroutine'}
45+
46+
for name in c_types.__all__:
47+
if name not in c_only_names | ignored:
48+
self.assertIs(getattr(c_types, name), getattr(py_types, name))
49+
50+
all_names = ignored | {
51+
'AsyncGeneratorType', 'BuiltinFunctionType', 'BuiltinMethodType',
52+
'CapsuleType', 'CellType', 'ClassMethodDescriptorType', 'CodeType',
53+
'CoroutineType', 'EllipsisType', 'FrameType', 'FunctionType',
54+
'GeneratorType', 'GenericAlias', 'GetSetDescriptorType',
55+
'LambdaType', 'MappingProxyType', 'MemberDescriptorType',
56+
'MethodDescriptorType', 'MethodType', 'MethodWrapperType',
57+
'ModuleType', 'NoneType', 'NotImplementedType', 'SimpleNamespace',
58+
'TracebackType', 'UnionType', 'WrapperDescriptorType',
59+
}
60+
self.assertEqual(all_names, set(c_types.__all__))
61+
self.assertEqual(all_names - c_only_names, set(py_types.__all__))
62+
3763
def test_truth_values(self):
3864
if None: self.fail('None is true instead of false')
3965
if 0: self.fail('0 is true instead of false')

Lib/types.py

+61-57
Original file line numberDiff line numberDiff line change
@@ -2,67 +2,78 @@
22
Define names for built-in types that aren't directly accessible as a builtin.
33
"""
44

5-
import _types
6-
75
# Iterators in Python aren't a matter of type but of protocol. A large
86
# and changing number of builtin types implement *some* flavor of
97
# iterator. Don't check the type! Use hasattr to check for both
108
# "__iter__" and "__next__" attributes instead.
119

12-
def _f(): pass
13-
FunctionType = type(_f)
14-
LambdaType = type(lambda: None) # Same as FunctionType
15-
CodeType = type(_f.__code__)
16-
MappingProxyType = type(type.__dict__)
17-
SimpleNamespace = _types.SimpleNamespace
18-
19-
def _cell_factory():
20-
a = 1
21-
def f():
22-
nonlocal a
23-
return f.__closure__[0]
24-
CellType = type(_cell_factory())
25-
26-
def _g():
27-
yield 1
28-
GeneratorType = type(_g())
29-
30-
async def _c(): pass
31-
_c = _c()
32-
CoroutineType = type(_c)
33-
_c.close() # Prevent ResourceWarning
34-
35-
async def _ag():
36-
yield
37-
_ag = _ag()
38-
AsyncGeneratorType = type(_ag)
39-
40-
class _C:
41-
def _m(self): pass
42-
MethodType = type(_C()._m)
43-
44-
BuiltinFunctionType = type(len)
45-
BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
10+
try:
11+
from _types import *
12+
except ImportError:
13+
import sys
14+
15+
def _f(): pass
16+
FunctionType = type(_f)
17+
LambdaType = type(lambda: None) # Same as FunctionType
18+
CodeType = type(_f.__code__)
19+
MappingProxyType = type(type.__dict__)
20+
SimpleNamespace = type(sys.implementation)
21+
22+
def _cell_factory():
23+
a = 1
24+
def f():
25+
nonlocal a
26+
return f.__closure__[0]
27+
CellType = type(_cell_factory())
28+
29+
def _g():
30+
yield 1
31+
GeneratorType = type(_g())
32+
33+
async def _c(): pass
34+
_c = _c()
35+
CoroutineType = type(_c)
36+
_c.close() # Prevent ResourceWarning
37+
38+
async def _ag():
39+
yield
40+
_ag = _ag()
41+
AsyncGeneratorType = type(_ag)
42+
43+
class _C:
44+
def _m(self): pass
45+
MethodType = type(_C()._m)
46+
47+
BuiltinFunctionType = type(len)
48+
BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
49+
50+
WrapperDescriptorType = type(object.__init__)
51+
MethodWrapperType = type(object().__str__)
52+
MethodDescriptorType = type(str.join)
53+
ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
54+
55+
ModuleType = type(sys)
4656

47-
WrapperDescriptorType = type(object.__init__)
48-
MethodWrapperType = type(object().__str__)
49-
MethodDescriptorType = type(str.join)
50-
ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
57+
try:
58+
raise TypeError
59+
except TypeError as exc:
60+
TracebackType = type(exc.__traceback__)
61+
FrameType = type(exc.__traceback__.tb_frame)
5162

52-
ModuleType = type(_types)
63+
GetSetDescriptorType = type(FunctionType.__code__)
64+
MemberDescriptorType = type(FunctionType.__globals__)
5365

54-
try:
55-
raise TypeError
56-
except TypeError as exc:
57-
TracebackType = type(exc.__traceback__)
58-
FrameType = type(exc.__traceback__.tb_frame)
66+
GenericAlias = type(list[int])
67+
UnionType = type(int | str)
5968

60-
GetSetDescriptorType = type(FunctionType.__code__)
61-
MemberDescriptorType = type(FunctionType.__globals__)
69+
EllipsisType = type(Ellipsis)
70+
NoneType = type(None)
71+
NotImplementedType = type(NotImplemented)
6272

63-
CapsuleType = _types.CapsuleType
73+
# CapsuleType cannot be accessed from pure Python,
74+
# so there is no fallback definition.
6475

65-
del _types, _f, _g, _C, _c, _ag, _cell_factory # Not for export
76+
del sys, _f, _g, _C, _c, _ag, _cell_factory # Not for export
6677

6778

6879
# Provide a PEP 3115 compliant mechanism for class creation
@@ -326,11 +337,4 @@ def wrapped(*args, **kwargs):
326337

327338
return wrapped
328339

329-
GenericAlias = type(list[int])
330-
UnionType = type(int | str)
331-
332-
EllipsisType = type(Ellipsis)
333-
NoneType = type(None)
334-
NotImplementedType = type(NotImplemented)
335-
336340
__all__ = [n for n in globals() if not n.startswith('_')] # for pydoc

Modules/_typesmodule.c

+41-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,52 @@
11
/* _types module */
22

33
#include "Python.h"
4+
#include "pycore_descrobject.h" // _PyMethodWrapper_Type
45
#include "pycore_namespace.h" // _PyNamespace_Type
6+
#include "pycore_object.h" // _PyNone_Type, _PyNotImplemented_Type
7+
#include "pycore_unionobject.h" // _PyUnion_Type
58

69
static int
710
_types_exec(PyObject *m)
811
{
9-
if (PyModule_AddObjectRef(m, "CapsuleType", (PyObject *)&PyCapsule_Type) < 0) {
10-
return -1;
11-
}
12-
if (PyModule_AddObjectRef(m, "SimpleNamespace", (PyObject *)&_PyNamespace_Type) < 0) {
13-
return -1;
14-
}
12+
#define EXPORT_STATIC_TYPE(NAME, TYPE) \
13+
do { \
14+
assert(PyUnstable_IsImmortal((PyObject *)&(TYPE))); \
15+
if (PyModule_AddObjectRef(m, (NAME), (PyObject *)&(TYPE)) < 0) { \
16+
return -1; \
17+
} \
18+
} while (0)
19+
20+
EXPORT_STATIC_TYPE("AsyncGeneratorType", PyAsyncGen_Type);
21+
EXPORT_STATIC_TYPE("BuiltinFunctionType", PyCFunction_Type);
22+
// BuiltinMethodType is the same as BuiltinFunctionType
23+
EXPORT_STATIC_TYPE("BuiltinMethodType", PyCFunction_Type);
24+
EXPORT_STATIC_TYPE("CapsuleType", PyCapsule_Type);
25+
EXPORT_STATIC_TYPE("CellType", PyCell_Type);
26+
EXPORT_STATIC_TYPE("ClassMethodDescriptorType", PyClassMethodDescr_Type);
27+
EXPORT_STATIC_TYPE("CodeType", PyCode_Type);
28+
EXPORT_STATIC_TYPE("CoroutineType", PyCoro_Type);
29+
EXPORT_STATIC_TYPE("EllipsisType", PyEllipsis_Type);
30+
EXPORT_STATIC_TYPE("FrameType", PyFrame_Type);
31+
EXPORT_STATIC_TYPE("FunctionType", PyFunction_Type);
32+
EXPORT_STATIC_TYPE("GeneratorType", PyGen_Type);
33+
EXPORT_STATIC_TYPE("GenericAlias", Py_GenericAliasType);
34+
EXPORT_STATIC_TYPE("GetSetDescriptorType", PyGetSetDescr_Type);
35+
// LambdaType is the same as FunctionType
36+
EXPORT_STATIC_TYPE("LambdaType", PyFunction_Type);
37+
EXPORT_STATIC_TYPE("MappingProxyType", PyDictProxy_Type);
38+
EXPORT_STATIC_TYPE("MemberDescriptorType", PyMemberDescr_Type);
39+
EXPORT_STATIC_TYPE("MethodDescriptorType", PyMethodDescr_Type);
40+
EXPORT_STATIC_TYPE("MethodType", PyMethod_Type);
41+
EXPORT_STATIC_TYPE("MethodWrapperType", _PyMethodWrapper_Type);
42+
EXPORT_STATIC_TYPE("ModuleType", PyModule_Type);
43+
EXPORT_STATIC_TYPE("NoneType", _PyNone_Type);
44+
EXPORT_STATIC_TYPE("NotImplementedType", _PyNotImplemented_Type);
45+
EXPORT_STATIC_TYPE("SimpleNamespace", _PyNamespace_Type);
46+
EXPORT_STATIC_TYPE("TracebackType", PyTraceBack_Type);
47+
EXPORT_STATIC_TYPE("UnionType", _PyUnion_Type);
48+
EXPORT_STATIC_TYPE("WrapperDescriptorType", PyWrapperDescr_Type);
49+
#undef EXPORT_STATIC_TYPE
1550
return 0;
1651
}
1752

0 commit comments

Comments
 (0)