GH-118761: Expose more core interpreter types in `_types` (#132103)

Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
This commit is contained in:
Adam Turner 2025-04-05 19:11:07 +01:00 committed by GitHub
parent 92fb949eac
commit 1755157207
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 130 additions and 65 deletions

View file

@ -4,6 +4,8 @@ from test.support import (
run_with_locale, cpython_only, no_rerun,
MISSING_C_DOCSTRINGS, EqualToForwardRef,
)
from test.support.import_helper import import_fresh_module
import collections.abc
from collections import namedtuple, UserDict
import copy
@ -19,6 +21,8 @@ import unittest.mock
import weakref
import typing
c_types = import_fresh_module('types', fresh=['_types'])
py_types = import_fresh_module('types', blocked=['_types'])
T = typing.TypeVar("T")
@ -34,6 +38,28 @@ def clear_typing_caches():
class TypesTests(unittest.TestCase):
def test_names(self):
c_only_names = {'CapsuleType'}
ignored = {'new_class', 'resolve_bases', 'prepare_class',
'get_original_bases', 'DynamicClassAttribute', 'coroutine'}
for name in c_types.__all__:
if name not in c_only_names | ignored:
self.assertIs(getattr(c_types, name), getattr(py_types, name))
all_names = ignored | {
'AsyncGeneratorType', 'BuiltinFunctionType', 'BuiltinMethodType',
'CapsuleType', 'CellType', 'ClassMethodDescriptorType', 'CodeType',
'CoroutineType', 'EllipsisType', 'FrameType', 'FunctionType',
'GeneratorType', 'GenericAlias', 'GetSetDescriptorType',
'LambdaType', 'MappingProxyType', 'MemberDescriptorType',
'MethodDescriptorType', 'MethodType', 'MethodWrapperType',
'ModuleType', 'NoneType', 'NotImplementedType', 'SimpleNamespace',
'TracebackType', 'UnionType', 'WrapperDescriptorType',
}
self.assertEqual(all_names, set(c_types.__all__))
self.assertEqual(all_names - c_only_names, set(py_types.__all__))
def test_truth_values(self):
if None: self.fail('None is true instead of false')
if 0: self.fail('0 is true instead of false')

View file

@ -2,67 +2,78 @@
Define names for built-in types that aren't directly accessible as a builtin.
"""
import _types
# Iterators in Python aren't a matter of type but of protocol. A large
# and changing number of builtin types implement *some* flavor of
# iterator. Don't check the type! Use hasattr to check for both
# "__iter__" and "__next__" attributes instead.
def _f(): pass
FunctionType = type(_f)
LambdaType = type(lambda: None) # Same as FunctionType
CodeType = type(_f.__code__)
MappingProxyType = type(type.__dict__)
SimpleNamespace = _types.SimpleNamespace
def _cell_factory():
a = 1
def f():
nonlocal a
return f.__closure__[0]
CellType = type(_cell_factory())
def _g():
yield 1
GeneratorType = type(_g())
async def _c(): pass
_c = _c()
CoroutineType = type(_c)
_c.close() # Prevent ResourceWarning
async def _ag():
yield
_ag = _ag()
AsyncGeneratorType = type(_ag)
class _C:
def _m(self): pass
MethodType = type(_C()._m)
BuiltinFunctionType = type(len)
BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
WrapperDescriptorType = type(object.__init__)
MethodWrapperType = type(object().__str__)
MethodDescriptorType = type(str.join)
ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
ModuleType = type(_types)
try:
raise TypeError
except TypeError as exc:
TracebackType = type(exc.__traceback__)
FrameType = type(exc.__traceback__.tb_frame)
from _types import *
except ImportError:
import sys
GetSetDescriptorType = type(FunctionType.__code__)
MemberDescriptorType = type(FunctionType.__globals__)
def _f(): pass
FunctionType = type(_f)
LambdaType = type(lambda: None) # Same as FunctionType
CodeType = type(_f.__code__)
MappingProxyType = type(type.__dict__)
SimpleNamespace = type(sys.implementation)
CapsuleType = _types.CapsuleType
def _cell_factory():
a = 1
def f():
nonlocal a
return f.__closure__[0]
CellType = type(_cell_factory())
del _types, _f, _g, _C, _c, _ag, _cell_factory # Not for export
def _g():
yield 1
GeneratorType = type(_g())
async def _c(): pass
_c = _c()
CoroutineType = type(_c)
_c.close() # Prevent ResourceWarning
async def _ag():
yield
_ag = _ag()
AsyncGeneratorType = type(_ag)
class _C:
def _m(self): pass
MethodType = type(_C()._m)
BuiltinFunctionType = type(len)
BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
WrapperDescriptorType = type(object.__init__)
MethodWrapperType = type(object().__str__)
MethodDescriptorType = type(str.join)
ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
ModuleType = type(sys)
try:
raise TypeError
except TypeError as exc:
TracebackType = type(exc.__traceback__)
FrameType = type(exc.__traceback__.tb_frame)
GetSetDescriptorType = type(FunctionType.__code__)
MemberDescriptorType = type(FunctionType.__globals__)
GenericAlias = type(list[int])
UnionType = type(int | str)
EllipsisType = type(Ellipsis)
NoneType = type(None)
NotImplementedType = type(NotImplemented)
# CapsuleType cannot be accessed from pure Python,
# so there is no fallback definition.
del sys, _f, _g, _C, _c, _ag, _cell_factory # Not for export
# Provide a PEP 3115 compliant mechanism for class creation
@ -326,11 +337,4 @@ def coroutine(func):
return wrapped
GenericAlias = type(list[int])
UnionType = type(int | str)
EllipsisType = type(Ellipsis)
NoneType = type(None)
NotImplementedType = type(NotImplemented)
__all__ = [n for n in globals() if not n.startswith('_')] # for pydoc

View file

@ -1,17 +1,52 @@
/* _types module */
#include "Python.h"
#include "pycore_descrobject.h" // _PyMethodWrapper_Type
#include "pycore_namespace.h" // _PyNamespace_Type
#include "pycore_object.h" // _PyNone_Type, _PyNotImplemented_Type
#include "pycore_unionobject.h" // _PyUnion_Type
static int
_types_exec(PyObject *m)
{
if (PyModule_AddObjectRef(m, "CapsuleType", (PyObject *)&PyCapsule_Type) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "SimpleNamespace", (PyObject *)&_PyNamespace_Type) < 0) {
return -1;
}
#define EXPORT_STATIC_TYPE(NAME, TYPE) \
do { \
assert(PyUnstable_IsImmortal((PyObject *)&(TYPE))); \
if (PyModule_AddObjectRef(m, (NAME), (PyObject *)&(TYPE)) < 0) { \
return -1; \
} \
} while (0)
EXPORT_STATIC_TYPE("AsyncGeneratorType", PyAsyncGen_Type);
EXPORT_STATIC_TYPE("BuiltinFunctionType", PyCFunction_Type);
// BuiltinMethodType is the same as BuiltinFunctionType
EXPORT_STATIC_TYPE("BuiltinMethodType", PyCFunction_Type);
EXPORT_STATIC_TYPE("CapsuleType", PyCapsule_Type);
EXPORT_STATIC_TYPE("CellType", PyCell_Type);
EXPORT_STATIC_TYPE("ClassMethodDescriptorType", PyClassMethodDescr_Type);
EXPORT_STATIC_TYPE("CodeType", PyCode_Type);
EXPORT_STATIC_TYPE("CoroutineType", PyCoro_Type);
EXPORT_STATIC_TYPE("EllipsisType", PyEllipsis_Type);
EXPORT_STATIC_TYPE("FrameType", PyFrame_Type);
EXPORT_STATIC_TYPE("FunctionType", PyFunction_Type);
EXPORT_STATIC_TYPE("GeneratorType", PyGen_Type);
EXPORT_STATIC_TYPE("GenericAlias", Py_GenericAliasType);
EXPORT_STATIC_TYPE("GetSetDescriptorType", PyGetSetDescr_Type);
// LambdaType is the same as FunctionType
EXPORT_STATIC_TYPE("LambdaType", PyFunction_Type);
EXPORT_STATIC_TYPE("MappingProxyType", PyDictProxy_Type);
EXPORT_STATIC_TYPE("MemberDescriptorType", PyMemberDescr_Type);
EXPORT_STATIC_TYPE("MethodDescriptorType", PyMethodDescr_Type);
EXPORT_STATIC_TYPE("MethodType", PyMethod_Type);
EXPORT_STATIC_TYPE("MethodWrapperType", _PyMethodWrapper_Type);
EXPORT_STATIC_TYPE("ModuleType", PyModule_Type);
EXPORT_STATIC_TYPE("NoneType", _PyNone_Type);
EXPORT_STATIC_TYPE("NotImplementedType", _PyNotImplemented_Type);
EXPORT_STATIC_TYPE("SimpleNamespace", _PyNamespace_Type);
EXPORT_STATIC_TYPE("TracebackType", PyTraceBack_Type);
EXPORT_STATIC_TYPE("UnionType", _PyUnion_Type);
EXPORT_STATIC_TYPE("WrapperDescriptorType", PyWrapperDescr_Type);
#undef EXPORT_STATIC_TYPE
return 0;
}