diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index f014f7e9ee08c9..671f396d75be70 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -4,6 +4,8 @@ run_with_locale, cpython_only, no_rerun, MISSING_C_DOCSTRINGS, ) +from test.support.import_helper import import_fresh_module + import collections.abc from collections import namedtuple, UserDict import copy @@ -19,6 +21,8 @@ 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') diff --git a/Lib/types.py b/Lib/types.py index 9aa0a3b087c1c7..6efac3394345a5 100644 --- a/Lib/types.py +++ b/Lib/types.py @@ -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 +try: + from _types import * +except ImportError: + import sys + + 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) + + 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(sys) -WrapperDescriptorType = type(object.__init__) -MethodWrapperType = type(object().__str__) -MethodDescriptorType = type(str.join) -ClassMethodDescriptorType = type(dict.__dict__['fromkeys']) + try: + raise TypeError + except TypeError as exc: + TracebackType = type(exc.__traceback__) + FrameType = type(exc.__traceback__.tb_frame) -ModuleType = type(_types) + GetSetDescriptorType = type(FunctionType.__code__) + MemberDescriptorType = type(FunctionType.__globals__) -try: - raise TypeError -except TypeError as exc: - TracebackType = type(exc.__traceback__) - FrameType = type(exc.__traceback__.tb_frame) + GenericAlias = type(list[int]) + UnionType = type(int | str) -GetSetDescriptorType = type(FunctionType.__code__) -MemberDescriptorType = type(FunctionType.__globals__) + EllipsisType = type(Ellipsis) + NoneType = type(None) + NotImplementedType = type(NotImplemented) -CapsuleType = _types.CapsuleType + # CapsuleType cannot be accessed from pure Python, + # so there is no fallback definition. -del _types, _f, _g, _C, _c, _ag, _cell_factory # Not for export + 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 wrapped(*args, **kwargs): 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 diff --git a/Modules/_typesmodule.c b/Modules/_typesmodule.c index aabb35f47eefc3..a30a88196e7192 100644 --- a/Modules/_typesmodule.c +++ b/Modules/_typesmodule.c @@ -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; }