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; }
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: