diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index ab627c28c1fa5e..bfc94e3e8529b7 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -26,6 +26,7 @@ extern int _Py_IsLocaleCoercionTarget(const char *ctype_loc); extern void _Py_InitVersion(void); extern PyStatus _PyFaulthandler_Init(int enable); extern PyObject * _PyBuiltin_Init(PyInterpreterState *interp); +extern int _PyBuiltin_InitPythonFunctions(PyObject *dict); extern PyStatus _PySys_Create( PyThreadState *tstate, PyObject **sysmod_p); diff --git a/Lib/_builtins.py b/Lib/_builtins.py new file mode 100644 index 00000000000000..4642a69b3aaf22 --- /dev/null +++ b/Lib/_builtins.py @@ -0,0 +1,42 @@ +"""Builtins implemented in Python. + +This module is frozen into the interpreter and imported during startup, +before the import system exists. The names listed in ``__all__`` are +copied into the ``builtins`` module. +""" + +__all__ = ['anext'] + +_NOT_GIVEN = object() + + +def anext(async_iterator, default=_NOT_GIVEN, /): + """Return the next item from the async iterator. + + If default is given and the async iterator is exhausted, + it is returned instead of raising StopAsyncIteration. + """ + cls = type(async_iterator) + try: + # Looked up on the type, like the C slot am_anext. + anext_method = cls.__anext__ + except AttributeError: + raise TypeError( + f"'{cls.__name__}' object is not an async iterator" + ) from None + awaitable = anext_method(async_iterator) + if default is _NOT_GIVEN: + return awaitable + return _anext_with_default(awaitable, default) + + +async def _anext_with_default(awaitable, default): + try: + return await awaitable + except StopAsyncIteration: + return default + + +for _name in __all__: + globals()[_name].__module__ = 'builtins' +del _name diff --git a/Lib/test/test_asyncio/test_graph.py b/Lib/test/test_asyncio/test_graph.py index a442a346ff06d9..1326ef50c149b0 100644 --- a/Lib/test/test_asyncio/test_graph.py +++ b/Lib/test/test_asyncio/test_graph.py @@ -148,6 +148,46 @@ async def main(): 'async generator CallStackTestBase.test_stack_async_gen..gen()', stack_for_gen_nested_call[1]) + async def test_stack_anext_default(self): + # anext() with a default wraps the awaitable in a coroutine, so the + # call graph of a suspended task sees through it into __anext__(). + + loop = asyncio.get_running_loop() + blocker = loop.create_future() + + async def inner(): + await blocker + + class AIter: + def __aiter__(self): + return self + + async def __anext__(self): + await inner() + return 1 + + async def main(): + await anext(AIter(), None) + + task = asyncio.create_task(main(), name='anext task') + await asyncio.sleep(0) + try: + stack = capture_test_stack(fut=task) + finally: + blocker.set_result(None) + await task + + self.assertEqual(stack[0], [ + 'T', + [ + 'a inner', + 'a __anext__', + 'a _anext_with_default', + 'a main', + ], + [] + ]) + def test_ag_frame_used_for_async_generator(self): # Regression test for gh-148736: the ag_await branch of # _build_graph_for_future must read ag_frame, not cr_frame. diff --git a/Lib/test/test_importlib/util.py b/Lib/test/test_importlib/util.py index 6399f952f9e912..4269940816ccaf 100644 --- a/Lib/test/test_importlib/util.py +++ b/Lib/test/test_importlib/util.py @@ -69,7 +69,8 @@ def import_importlib(module_name): fresh = ('importlib',) if '.' in module_name else () frozen = import_helper.import_fresh_module(module_name) source = import_helper.import_fresh_module(module_name, fresh=fresh, - blocked=('_frozen_importlib', '_frozen_importlib_external')) + blocked=('_frozen_importlib', '_frozen_importlib_external', + '_builtins')) return {'Frozen': frozen, 'Source': source} diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index df5843abfcb875..25276fc40cb028 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -6174,7 +6174,7 @@ def test_builtins_have_signatures(self): "next", "vars"} no_signature |= needs_groups # These have unrepresentable parameter default values of NULL - unsupported_signature = {"anext", "aiter", "iter"} + unsupported_signature = {"aiter", "iter"} # These need *args support in Argument Clinic needs_varargs = {"min", "max", "__build_class__"} no_signature |= needs_varargs diff --git a/Makefile.pre.in b/Makefile.pre.in index 78a486623181fa..9d5deb3902fd36 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1623,7 +1623,8 @@ Programs/_testembed: Programs/_testembed.o $(LINK_PYTHON_DEPS) BOOTSTRAP_HEADERS = \ Python/frozen_modules/importlib._bootstrap.h \ Python/frozen_modules/importlib._bootstrap_external.h \ - Python/frozen_modules/zipimport.h + Python/frozen_modules/zipimport.h \ + Python/frozen_modules/_builtins.h Programs/_bootstrap_python.o: Programs/_bootstrap_python.c $(BOOTSTRAP_HEADERS) $(PYTHON_HEADERS) @@ -1664,6 +1665,7 @@ FROZEN_FILES_IN = \ Lib/importlib/_bootstrap.py \ Lib/importlib/_bootstrap_external.py \ Lib/zipimport.py \ + Lib/_builtins.py \ Lib/abc.py \ Lib/codecs.py \ Lib/io.py \ @@ -1690,6 +1692,7 @@ FROZEN_FILES_OUT = \ Python/frozen_modules/importlib._bootstrap.h \ Python/frozen_modules/importlib._bootstrap_external.h \ Python/frozen_modules/zipimport.h \ + Python/frozen_modules/_builtins.h \ Python/frozen_modules/abc.h \ Python/frozen_modules/codecs.h \ Python/frozen_modules/io.h \ @@ -1735,6 +1738,9 @@ Python/frozen_modules/importlib._bootstrap_external.h: Lib/importlib/_bootstrap_ Python/frozen_modules/zipimport.h: Lib/zipimport.py $(FREEZE_MODULE_BOOTSTRAP_DEPS) $(FREEZE_MODULE_BOOTSTRAP) zipimport $(srcdir)/Lib/zipimport.py Python/frozen_modules/zipimport.h +Python/frozen_modules/_builtins.h: Lib/_builtins.py $(FREEZE_MODULE_BOOTSTRAP_DEPS) + $(FREEZE_MODULE_BOOTSTRAP) _builtins $(srcdir)/Lib/_builtins.py Python/frozen_modules/_builtins.h + Python/frozen_modules/abc.h: Lib/abc.py $(FREEZE_MODULE_DEPS) $(FREEZE_MODULE) abc $(srcdir)/Lib/abc.py Python/frozen_modules/abc.h diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-12-16-40-00.gh-issue-157361.anextpy.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-12-16-40-00.gh-issue-157361.anextpy.rst new file mode 100644 index 00000000000000..c78e75b723e0d1 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-12-16-40-00.gh-issue-157361.anextpy.rst @@ -0,0 +1,4 @@ +Implement :func:`anext` in Python instead of C, in a frozen ``_builtins`` +module. The awaitable returned by ``anext(it, default)`` is now a plain +coroutine, so introspection tools such as :func:`asyncio.print_call_graph` +can see through it into :meth:`~object.__anext__`. diff --git a/Objects/iterobject.c b/Objects/iterobject.c index b5783c92c8eb68..2d5e3709a27dfb 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -403,33 +403,6 @@ PyTypeObject PyCallIter_Type = { /* -------------------------------------- */ -typedef struct { - PyObject_HEAD - PyObject *wrapped; - PyObject *default_value; -} anextawaitableobject; - -#define anextawaitableobject_CAST(op) ((anextawaitableobject *)(op)) - -static void -anextawaitable_dealloc(PyObject *op) -{ - anextawaitableobject *obj = anextawaitableobject_CAST(op); - _PyObject_GC_UNTRACK(obj); - Py_XDECREF(obj->wrapped); - Py_XDECREF(obj->default_value); - PyObject_GC_Del(obj); -} - -static int -anextawaitable_traverse(PyObject *op, visitproc visit, void *arg) -{ - anextawaitableobject *obj = anextawaitableobject_CAST(op); - Py_VISIT(obj->wrapped); - Py_VISIT(obj->default_value); - return 0; -} - static PyObject * awaitable_getiter(PyObject *owner, PyObject *wrapped) { @@ -461,99 +434,6 @@ awaitable_getiter(PyObject *owner, PyObject *wrapped) return awaitable; } -static PyObject * -anextawaitable_iternext(PyObject *op) -{ - /* Consider the following class: - * - * class A: - * async def __anext__(self): - * ... - * a = A() - * - * Then `await anext(a)` should call - * a.__anext__().__await__().__next__() - * - * On the other hand, given - * - * async def agen(): - * yield 1 - * yield 2 - * gen = agen() - * - * Then `await anext(gen)` can just call - * gen.__anext__().__next__() - */ - anextawaitableobject *obj = anextawaitableobject_CAST(op); - PyObject *awaitable = awaitable_getiter(op, obj->wrapped); - if (awaitable == NULL) { - return NULL; - } - PyObject *result = (*Py_TYPE(awaitable)->tp_iternext)(awaitable); - Py_DECREF(awaitable); - if (result != NULL) { - return result; - } - if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) { - PyErr_Clear(); - _PyGen_SetStopIterationValue(obj->default_value); - } - return NULL; -} - - -static PyObject * -anextawaitable_proxy(anextawaitableobject *obj, char *meth, PyObject *arg) -{ - PyObject *awaitable = awaitable_getiter((PyObject *)obj, obj->wrapped); - if (awaitable == NULL) { - return NULL; - } - // When specified, 'arg' may be a tuple (if coming from a METH_VARARGS - // method) or a single object (if coming from a METH_O method). - PyObject *ret = arg == NULL - ? PyObject_CallMethod(awaitable, meth, NULL) - : PyObject_CallMethod(awaitable, meth, "O", arg); - Py_DECREF(awaitable); - if (ret != NULL) { - return ret; - } - if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) { - /* `anextawaitableobject` is only used by `anext()` when - * a default value is provided. So when we have a StopAsyncIteration - * exception we replace it with a `StopIteration(default)`, as if - * it was the return value of `__anext__()` coroutine. - */ - PyErr_Clear(); - _PyGen_SetStopIterationValue(obj->default_value); - } - return NULL; -} - - -static PyObject * -anextawaitable_send(PyObject *op, PyObject *arg) -{ - anextawaitableobject *obj = anextawaitableobject_CAST(op); - return anextawaitable_proxy(obj, "send", arg); -} - - -static PyObject * -anextawaitable_throw(PyObject *op, PyObject *args) -{ - anextawaitableobject *obj = anextawaitableobject_CAST(op); - return anextawaitable_proxy(obj, "throw", args); -} - - -static PyObject * -anextawaitable_close(PyObject *op, PyObject *Py_UNUSED(dummy)) -{ - anextawaitableobject *obj = anextawaitableobject_CAST(op); - return anextawaitable_proxy(obj, "close", NULL); -} - PyDoc_STRVAR(send_doc, "send(arg) -> send 'arg' into the wrapped iterator,\n\ @@ -574,68 +454,6 @@ PyDoc_STRVAR(close_doc, "close() -> raise GeneratorExit inside generator."); -static PyMethodDef anextawaitable_methods[] = { - {"send", anextawaitable_send, METH_O, send_doc}, - {"throw", anextawaitable_throw, METH_VARARGS, throw_doc}, - {"close", anextawaitable_close, METH_NOARGS, close_doc}, - {NULL, NULL} /* Sentinel */ -}; - - -static PyAsyncMethods anextawaitable_as_async = { - PyObject_SelfIter, /* am_await */ - 0, /* am_aiter */ - 0, /* am_anext */ - 0, /* am_send */ -}; - -PyTypeObject _PyAnextAwaitable_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "anext_awaitable", /* tp_name */ - sizeof(anextawaitableobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - anextawaitable_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - &anextawaitable_as_async, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - anextawaitable_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - anextawaitable_iternext, /* tp_iternext */ - anextawaitable_methods, /* tp_methods */ -}; - -PyObject * -PyAnextAwaitable_New(PyObject *awaitable, PyObject *default_value) -{ - anextawaitableobject *anext = PyObject_GC_New( - anextawaitableobject, &_PyAnextAwaitable_Type); - if (anext == NULL) { - return NULL; - } - anext->wrapped = Py_NewRef(awaitable); - anext->default_value = Py_NewRef(default_value); - _PyObject_GC_TRACK(anext); - return (PyObject *)anext; -} - - /* -------------------------------------- */ /* The asynchronous counterpart of calliterobject: the callable is called diff --git a/Objects/object.c b/Objects/object.c index a83f8d4c04ca07..e3f29b71301695 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2522,7 +2522,6 @@ _PyObject_FiniState(PyInterpreterState *interp) extern PyTypeObject _PyACallIter_Type; extern PyTypeObject _PyACallIterAwaitable_Type; -extern PyTypeObject _PyAnextAwaitable_Type; extern PyTypeObject _PyLegacyEventHandler_Type; extern PyTypeObject _PyLineIterator; extern PyTypeObject _PyMemoryIter_Type; @@ -2617,7 +2616,6 @@ static PyTypeObject* static_types[_Py_NUM_MANAGED_PREINITIALIZED_TYPES] = { &Py_GenericAliasType, &_PyACallIter_Type, &_PyACallIterAwaitable_Type, - &_PyAnextAwaitable_Type, &_PyAsyncGenASend_Type, &_PyAsyncGenAThrow_Type, &_PyAsyncGenWrappedValue_Type, diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj index 469fd77cc8be9d..94eaee0f7c0dd1 100644 --- a/PCbuild/_freeze_module.vcxproj +++ b/PCbuild/_freeze_module.vcxproj @@ -306,6 +306,11 @@ $(IntDir)zipimport.g.h $(GeneratedFrozenModulesDir)Python\frozen_modules\zipimport.h + + _builtins + $(IntDir)_builtins.g.h + $(GeneratedFrozenModulesDir)Python\frozen_modules\_builtins.h + abc $(IntDir)abc.g.h diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters index 976c99b7d24bdf..bc3f4df5d874ab 100644 --- a/PCbuild/_freeze_module.vcxproj.filters +++ b/PCbuild/_freeze_module.vcxproj.filters @@ -549,6 +549,9 @@ Python Files + + Python Files + Python Files diff --git a/Programs/_bootstrap_python.c b/Programs/_bootstrap_python.c index 6443d814a22dab..5509e977711709 100644 --- a/Programs/_bootstrap_python.c +++ b/Programs/_bootstrap_python.c @@ -13,6 +13,7 @@ #include "Python/frozen_modules/importlib._bootstrap.h" #include "Python/frozen_modules/importlib._bootstrap_external.h" #include "Python/frozen_modules/zipimport.h" +#include "Python/frozen_modules/_builtins.h" /* End includes */ /* Note that a negative size indicates a package. */ @@ -21,6 +22,7 @@ static const struct _frozen bootstrap_modules[] = { {"_frozen_importlib", _Py_M__importlib__bootstrap, (int)sizeof(_Py_M__importlib__bootstrap)}, {"_frozen_importlib_external", _Py_M__importlib__bootstrap_external, (int)sizeof(_Py_M__importlib__bootstrap_external)}, {"zipimport", _Py_M__zipimport, (int)sizeof(_Py_M__zipimport)}, + {"_builtins", _Py_M___builtins, (int)sizeof(_Py_M___builtins)}, {0, 0, 0} /* bootstrap sentinel */ }; static const struct _frozen stdlib_modules[] = { diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index d28e6fa9cd01ae..9ef1dd5e9980a5 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -1960,52 +1960,6 @@ builtin_aiter_impl(PyObject *module, PyObject *object, PyObject *stop_value, return _PyACallIter_New(object, stop_value, stop_exception); } -PyObject *PyAnextAwaitable_New(PyObject *, PyObject *); - -/*[clinic input] -anext as builtin_anext - - async_iterator as aiterator: object - default: object = NULL - / - -Return the next item from the async iterator. - -If default is given and the async iterator is exhausted, -it is returned instead of raising StopAsyncIteration. -[clinic start generated code]*/ - -static PyObject * -builtin_anext_impl(PyObject *module, PyObject *aiterator, - PyObject *default_value) -/*[clinic end generated code: output=f02c060c163a81fa input=f3dc5a93f073e5ac]*/ -{ - PyTypeObject *t; - PyObject *awaitable; - - t = Py_TYPE(aiterator); - if (t->tp_as_async == NULL || t->tp_as_async->am_anext == NULL) { - PyErr_Format(PyExc_TypeError, - "'%.200s' object is not an async iterator", - t->tp_name); - return NULL; - } - - awaitable = (*t->tp_as_async->am_anext)(aiterator); - if (awaitable == NULL) { - return NULL; - } - if (default_value == NULL) { - return awaitable; - } - - PyObject* new_awaitable = PyAnextAwaitable_New( - awaitable, default_value); - Py_DECREF(awaitable); - return new_awaitable; -} - - /*[clinic input] len as builtin_len @@ -3500,7 +3454,6 @@ static PyMethodDef builtin_methods[] = { {"max", _PyCFunction_CAST(builtin_max), METH_FASTCALL | METH_KEYWORDS, max_doc}, {"min", _PyCFunction_CAST(builtin_min), METH_FASTCALL | METH_KEYWORDS, min_doc}, {"next", _PyCFunction_CAST(builtin_next), METH_FASTCALL, next_doc}, - BUILTIN_ANEXT_METHODDEF BUILTIN_OCT_METHODDEF BUILTIN_ORD_METHODDEF BUILTIN_POW_METHODDEF @@ -3539,6 +3492,57 @@ static struct PyModuleDef builtinsmodule = { }; +/* Builtins implemented in Python. + + Lib/_builtins.py is frozen into the interpreter as a bootstrap module + (see Tools/build/freeze_modules.py), so it can be imported here before + the import system exists. The names in its __all__ are copied into the + builtins dict. */ + +int +_PyBuiltin_InitPythonFunctions(PyObject *dict) +{ + if (PyImport_ImportFrozenModule("_builtins") <= 0) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, + "frozen module _builtins not found"); + } + return -1; + } + PyObject *mod = PyImport_AddModuleRef("_builtins"); + if (mod == NULL) { + return -1; + } + + int rc = -1; + PyObject *all = PyObject_GetAttr(mod, &_Py_ID(__all__)); + if (all == NULL) { + goto done; + } + Py_ssize_t n = PyList_Size(all); + if (n < 0) { + goto done; + } + for (Py_ssize_t i = 0; i < n; i++) { + PyObject *name = PyList_GET_ITEM(all, i); + PyObject *func = PyObject_GetAttr(mod, name); + if (func == NULL) { + goto done; + } + int r = PyDict_SetItem(dict, name, func); + Py_DECREF(func); + if (r < 0) { + goto done; + } + } + rc = 0; + +done: + Py_XDECREF(all); + Py_DECREF(mod); + return rc; +} + PyObject * _PyBuiltin_Init(PyInterpreterState *interp) { diff --git a/Python/clinic/bltinmodule.c.h b/Python/clinic/bltinmodule.c.h index c10bb03d817816..5858ca9ff88ec2 100644 --- a/Python/clinic/bltinmodule.c.h +++ b/Python/clinic/bltinmodule.c.h @@ -1011,44 +1011,6 @@ builtin_aiter(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec return return_value; } -PyDoc_STRVAR(builtin_anext__doc__, -"anext($module, async_iterator, default=, /)\n" -"--\n" -"\n" -"Return the next item from the async iterator.\n" -"\n" -"If default is given and the async iterator is exhausted,\n" -"it is returned instead of raising StopAsyncIteration."); - -#define BUILTIN_ANEXT_METHODDEF \ - {"anext", _PyCFunction_CAST(builtin_anext), METH_FASTCALL, builtin_anext__doc__}, - -static PyObject * -builtin_anext_impl(PyObject *module, PyObject *aiterator, - PyObject *default_value); - -static PyObject * -builtin_anext(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -{ - PyObject *return_value = NULL; - PyObject *aiterator; - PyObject *default_value = NULL; - - if (!_PyArg_CheckPositional("anext", nargs, 1, 2)) { - goto exit; - } - aiterator = args[0]; - if (nargs < 2) { - goto skip_optional; - } - default_value = args[1]; -skip_optional: - return_value = builtin_anext_impl(module, aiterator, default_value); - -exit: - return return_value; -} - PyDoc_STRVAR(builtin_len__doc__, "len($module, obj, /)\n" "--\n" @@ -1539,4 +1501,4 @@ builtin_issubclass(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=5fb1ac6a4253ee2f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b56739f2e13f616a input=a9049054013a1b77]*/ diff --git a/Python/frozen.c b/Python/frozen.c index 9433d90c15e2ec..b1fd0fb427298b 100644 --- a/Python/frozen.c +++ b/Python/frozen.c @@ -44,6 +44,7 @@ #include "frozen_modules/importlib._bootstrap.h" #include "frozen_modules/importlib._bootstrap_external.h" #include "frozen_modules/zipimport.h" +#include "frozen_modules/_builtins.h" #include "frozen_modules/abc.h" #include "frozen_modules/codecs.h" #include "frozen_modules/io.h" @@ -71,6 +72,7 @@ static const struct _frozen bootstrap_modules[] = { {"_frozen_importlib", _Py_M__importlib__bootstrap, (int)sizeof(_Py_M__importlib__bootstrap), false}, {"_frozen_importlib_external", _Py_M__importlib__bootstrap_external, (int)sizeof(_Py_M__importlib__bootstrap_external), false}, {"zipimport", _Py_M__zipimport, (int)sizeof(_Py_M__zipimport), false}, + {"_builtins", _Py_M___builtins, (int)sizeof(_Py_M___builtins), false}, {0, 0, 0} /* bootstrap sentinel */ }; static const struct _frozen stdlib_modules[] = { diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 500a1a1949a5a8..e4b0258706714f 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -924,6 +924,16 @@ pycore_init_builtins(PyThreadState *tstate) return _PyStatus_ERR("failed to add exceptions to builtins"); } + /* The Python-implemented builtins live in the frozen _builtins module. + Programs/_freeze_module has no frozen modules (it's what creates + them) and opts out via _install_importlib, like the import system. */ + const PyConfig *config = _PyInterpreterState_GetConfig(interp); + if (config->_install_importlib) { + if (_PyBuiltin_InitPythonFunctions(builtins_dict) < 0) { + return _PyStatus_ERR("failed to add Python-implemented builtins"); + } + } + interp->builtins_copy = PyDict_Copy(interp->builtins); if (interp->builtins_copy == NULL) { goto error; diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index 8937e666bbbdd5..bd5db458c0e89f 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -12,6 +12,7 @@ static const char* _Py_stdlib_module_names[] = { "_asyncio", "_bisect", "_blake2", +"_builtins", "_bz2", "_codecs", "_codecs_cn", diff --git a/Tools/build/freeze_modules.py b/Tools/build/freeze_modules.py index a866336fa78879..5cfa6141fd41db 100644 --- a/Tools/build/freeze_modules.py +++ b/Tools/build/freeze_modules.py @@ -45,6 +45,8 @@ # This module is important because some Python builds rely # on a builtin zip file instead of a filesystem. 'zipimport', + # Builtins implemented in Python; loaded while builtins is set up. + '_builtins', ]), # (You can delete entries from here down to the end of the list.) ('stdlib - startup, without site (python -S)', [ @@ -91,6 +93,7 @@ 'importlib._bootstrap', 'importlib._bootstrap_external', 'zipimport', + '_builtins', } diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index b8488899c4595d..67ced170243e4a 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -60,7 +60,6 @@ Objects/iterobject.c - PyCallIter_Type - Objects/iterobject.c - PySeqIter_Type - Objects/iterobject.c - _PyACallIter_Type - Objects/iterobject.c - _PyACallIterAwaitable_Type - -Objects/iterobject.c - _PyAnextAwaitable_Type - Objects/lazyimportobject.c - PyLazyImport_Type - Objects/listobject.c - PyListIter_Type - Objects/listobject.c - PyListRevIter_Type - @@ -77,7 +76,6 @@ Objects/object.c - _PyNone_Type - Objects/object.c - _PyNotImplemented_Type - Objects/object.c - _PyACallIter_Type - Objects/object.c - _PyACallIterAwaitable_Type - -Objects/object.c - _PyAnextAwaitable_Type - Objects/odictobject.c - PyODictItems_Type - Objects/odictobject.c - PyODictIter_Type - Objects/odictobject.c - PyODictKeys_Type -