event loops, as done in the :file:`Modules/_tkinter.c` in the
Python source code.
+ .. versionchanged:: 3.12
+ This function is only called from the
+ :ref:`main interpreter <sub-interpreter-support>`.
+
.. c:var:: char* (*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, const char *)
:c:func:`PyMem_RawRealloc`, instead of being allocated by
:c:func:`PyMem_Malloc` or :c:func:`PyMem_Realloc`.
+ .. versionchanged:: 3.12
+ This function is only called from the
+ :ref:`main interpreter <sub-interpreter-support>`.
+
.. c:function:: PyObject* PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals)
This is a simplified interface to :c:func:`PyRun_StringFlags` below, leaving
Note that :c:func:`PyType_FromMetaclass` (added in Python 3.12)
already disallows creating classes whose metaclass overrides ``tp_new``.
+* :c:var:`PyOS_InputHook` and :c:var:`PyOS_ReadlineFunctionPointer` are no
+ longer called in :ref:`subinterpreters <sub-interpreter-support>`. This is
+ because clients generally rely on process-wide global state (since these
+ callbacks have no way of recovering extension module state).
+
+ This also avoids situations where extensions may find themselves running in a
+ subinterpreter that they don't support (or haven't yet been loaded in). See
+ :gh:`104668` for more info.
+
Deprecated
----------
#endif
while (1) {
- if (PyOS_InputHook != NULL) {
+ if (PyOS_InputHook != NULL &&
+ // GH-104668: See PyOS_ReadlineFunctionPointer's comment below...
+ _Py_IsMainInterpreter(tstate->interp))
+ {
(void)(PyOS_InputHook)();
}
wbuf = wbuf_local;
wbuflen = sizeof(wbuf_local) / sizeof(wbuf_local[0]) - 1;
while (1) {
- if (PyOS_InputHook != NULL) {
+ if (PyOS_InputHook != NULL &&
+ // GH-104668: See PyOS_ReadlineFunctionPointer's comment below...
+ _Py_IsMainInterpreter(tstate->interp))
+ {
(void)(PyOS_InputHook)();
}
if (!ReadConsoleW(hStdIn, &wbuf[total_read], wbuflen - total_read, &n_read, NULL)) {
* a tty. This can happen, for example if python is run like
* this: python -i < test1.py
*/
- if (!isatty (fileno (sys_stdin)) || !isatty (fileno (sys_stdout)))
- rv = PyOS_StdioReadline (sys_stdin, sys_stdout, prompt);
- else
- rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout,
- prompt);
+ if (!isatty(fileno(sys_stdin)) || !isatty(fileno(sys_stdout)) ||
+ // GH-104668: Don't call global callbacks like PyOS_InputHook or
+ // PyOS_ReadlineFunctionPointer from subinterpreters, since it seems
+ // like there's no good way for users (like readline and tkinter) to
+ // avoid using global state to manage them. Plus, we generally don't
+ // want to cause trouble for libraries that don't know/care about
+ // subinterpreter support. If libraries really need better APIs that
+ // work per-interpreter and have ways to access module state, we can
+ // certainly add them later (but for now we'll cross our fingers and
+ // hope that nobody actually cares):
+ !_Py_IsMainInterpreter(tstate->interp))
+ {
+ rv = PyOS_StdioReadline(sys_stdin, sys_stdout, prompt);
+ }
+ else {
+ rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout, prompt);
+ }
Py_END_ALLOW_THREADS
PyThread_release_lock(_PyOS_ReadlineLock);