Skip to content

Commit 2e15f83

Browse files
Merge branch 'main' into unhandledexc
2 parents b3edf63 + 794dff2 commit 2e15f83

File tree

84 files changed

+2946
-1928
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+2946
-1928
lines changed

Doc/using/cmdline.rst

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -535,12 +535,13 @@ Miscellaneous options
535535
location indicators when the interpreter displays tracebacks. See also
536536
:envvar:`PYTHONNODEBUGRANGES`.
537537
* ``-X frozen_modules`` determines whether or not frozen modules are
538-
ignored by the import machinery. A value of "on" means they get
539-
imported and "off" means they are ignored. The default is "on"
538+
ignored by the import machinery. A value of ``on`` means they get
539+
imported and ``off`` means they are ignored. The default is ``on``
540540
if this is an installed Python (the normal case). If it's under
541-
development (running from the source tree) then the default is "off".
542-
Note that the "importlib_bootstrap" and "importlib_bootstrap_external"
543-
frozen modules are always used, even if this flag is set to "off".
541+
development (running from the source tree) then the default is ``off``.
542+
Note that the :mod:`!importlib_bootstrap` and
543+
:mod:`!importlib_bootstrap_external` frozen modules are always used, even
544+
if this flag is set to ``off``. See also :envvar:`PYTHON_FROZEN_MODULES`.
544545
* ``-X perf`` enables support for the Linux ``perf`` profiler.
545546
When this option is provided, the ``perf`` profiler will be able to
546547
report Python calls. This option is only available on some platforms and
@@ -1095,6 +1096,20 @@ conflict.
10951096

10961097
.. versionadded:: 3.13
10971098

1099+
.. envvar:: PYTHON_FROZEN_MODULES
1100+
1101+
If this variable is set to ``on`` or ``off``, it determines whether or not
1102+
frozen modules are ignored by the import machinery. A value of ``on`` means
1103+
they get imported and ``off`` means they are ignored. The default is ``on``
1104+
for non-debug builds (the normal case) and ``off`` for debug builds.
1105+
Note that the :mod:`!importlib_bootstrap` and
1106+
:mod:`!importlib_bootstrap_external` frozen modules are always used, even
1107+
if this flag is set to ``off``.
1108+
1109+
See also the :option:`-X frozen_modules <-X>` command-line option.
1110+
1111+
.. versionadded:: 3.13
1112+
10981113

10991114
Debug-mode variables
11001115
~~~~~~~~~~~~~~~~~~~~

Doc/whatsnew/3.13.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@ Other Language Changes
120120
is rejected when the global is used in the :keyword:`else` block.
121121
(Contributed by Irit Katriel in :gh:`111123`.)
122122

123+
* Added a new environment variable :envvar:`PYTHON_FROZEN_MODULES`. It
124+
determines whether or not frozen modules are ignored by the import machinery,
125+
equivalent of the :option:`-X frozen_modules <-X>` command-line option.
126+
(Contributed by Yilei Yang in :gh:`111374`.)
127+
123128
New Modules
124129
===========
125130

@@ -1035,7 +1040,8 @@ New Features
10351040
* If Python is built in :ref:`debug mode <debug-build>` or :option:`with
10361041
assertions <--with-assertions>`, :c:func:`PyTuple_SET_ITEM` and
10371042
:c:func:`PyList_SET_ITEM` now check the index argument with an assertion.
1038-
If the assertion fails, make sure that the size is set before.
1043+
If the assertion fails in :c:func:`PyTuple_SET_ITEM`, make sure that the
1044+
tuple size is set before.
10391045
(Contributed by Victor Stinner in :gh:`106168`.)
10401046

10411047
* Add :c:func:`PyModule_Add` function: similar to

Include/internal/pycore_crossinterp.h

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11+
#include "pycore_pyerrors.h"
12+
1113

1214
/***************************/
1315
/* cross-interpreter calls */
@@ -124,6 +126,8 @@ struct _xidregitem {
124126
};
125127

126128
struct _xidregistry {
129+
int global; /* builtin types or heap types */
130+
int initialized;
127131
PyThread_type_lock mutex;
128132
struct _xidregitem *head;
129133
};
@@ -133,6 +137,130 @@ PyAPI_FUNC(int) _PyCrossInterpreterData_UnregisterClass(PyTypeObject *);
133137
PyAPI_FUNC(crossinterpdatafunc) _PyCrossInterpreterData_Lookup(PyObject *);
134138

135139

140+
/*****************************/
141+
/* runtime state & lifecycle */
142+
/*****************************/
143+
144+
struct _xi_runtime_state {
145+
// builtin types
146+
// XXX Remove this field once we have a tp_* slot.
147+
struct _xidregistry registry;
148+
};
149+
150+
struct _xi_state {
151+
// heap types
152+
// XXX Remove this field once we have a tp_* slot.
153+
struct _xidregistry registry;
154+
155+
// heap types
156+
PyObject *PyExc_NotShareableError;
157+
};
158+
159+
extern PyStatus _PyXI_Init(PyInterpreterState *interp);
160+
extern void _PyXI_Fini(PyInterpreterState *interp);
161+
162+
163+
/***************************/
164+
/* short-term data sharing */
165+
/***************************/
166+
167+
typedef enum error_code {
168+
_PyXI_ERR_NO_ERROR = 0,
169+
_PyXI_ERR_UNCAUGHT_EXCEPTION = -1,
170+
_PyXI_ERR_OTHER = -2,
171+
_PyXI_ERR_NO_MEMORY = -3,
172+
_PyXI_ERR_ALREADY_RUNNING = -4,
173+
_PyXI_ERR_MAIN_NS_FAILURE = -5,
174+
_PyXI_ERR_APPLY_NS_FAILURE = -6,
175+
_PyXI_ERR_NOT_SHAREABLE = -7,
176+
} _PyXI_errcode;
177+
178+
179+
typedef struct _sharedexception {
180+
// The originating interpreter.
181+
PyInterpreterState *interp;
182+
// The kind of error to propagate.
183+
_PyXI_errcode code;
184+
// The exception information to propagate, if applicable.
185+
// This is populated only for _PyXI_ERR_UNCAUGHT_EXCEPTION.
186+
_Py_excinfo uncaught;
187+
} _PyXI_exception_info;
188+
189+
PyAPI_FUNC(void) _PyXI_ApplyExceptionInfo(
190+
_PyXI_exception_info *info,
191+
PyObject *exctype);
192+
193+
typedef struct xi_session _PyXI_session;
194+
typedef struct _sharedns _PyXI_namespace;
195+
196+
PyAPI_FUNC(void) _PyXI_FreeNamespace(_PyXI_namespace *ns);
197+
PyAPI_FUNC(_PyXI_namespace *) _PyXI_NamespaceFromNames(PyObject *names);
198+
PyAPI_FUNC(int) _PyXI_FillNamespaceFromDict(
199+
_PyXI_namespace *ns,
200+
PyObject *nsobj,
201+
_PyXI_session *session);
202+
PyAPI_FUNC(int) _PyXI_ApplyNamespace(
203+
_PyXI_namespace *ns,
204+
PyObject *nsobj,
205+
PyObject *dflt);
206+
207+
208+
// A cross-interpreter session involves entering an interpreter
209+
// (_PyXI_Enter()), doing some work with it, and finally exiting
210+
// that interpreter (_PyXI_Exit()).
211+
//
212+
// At the boundaries of the session, both entering and exiting,
213+
// data may be exchanged between the previous interpreter and the
214+
// target one in a thread-safe way that does not violate the
215+
// isolation between interpreters. This includes setting objects
216+
// in the target's __main__ module on the way in, and capturing
217+
// uncaught exceptions on the way out.
218+
struct xi_session {
219+
// Once a session has been entered, this is the tstate that was
220+
// current before the session. If it is different from cur_tstate
221+
// then we must have switched interpreters. Either way, this will
222+
// be the current tstate once we exit the session.
223+
PyThreadState *prev_tstate;
224+
// Once a session has been entered, this is the current tstate.
225+
// It must be current when the session exits.
226+
PyThreadState *init_tstate;
227+
// This is true if init_tstate needs cleanup during exit.
228+
int own_init_tstate;
229+
230+
// This is true if, while entering the session, init_thread took
231+
// "ownership" of the interpreter's __main__ module. This means
232+
// it is the only thread that is allowed to run code there.
233+
// (Caveat: for now, users may still run exec() against the
234+
// __main__ module's dict, though that isn't advisable.)
235+
int running;
236+
// This is a cached reference to the __dict__ of the entered
237+
// interpreter's __main__ module. It is looked up when at the
238+
// beginning of the session as a convenience.
239+
PyObject *main_ns;
240+
241+
// This is set if the interpreter is entered and raised an exception
242+
// that needs to be handled in some special way during exit.
243+
_PyXI_errcode *exc_override;
244+
// This is set if exit captured an exception to propagate.
245+
_PyXI_exception_info *exc;
246+
247+
// -- pre-allocated memory --
248+
_PyXI_exception_info _exc;
249+
_PyXI_errcode _exc_override;
250+
};
251+
252+
PyAPI_FUNC(int) _PyXI_Enter(
253+
_PyXI_session *session,
254+
PyInterpreterState *interp,
255+
PyObject *nsupdates);
256+
PyAPI_FUNC(void) _PyXI_Exit(_PyXI_session *session);
257+
258+
PyAPI_FUNC(void) _PyXI_ApplyCapturedException(
259+
_PyXI_session *session,
260+
PyObject *excwrapper);
261+
PyAPI_FUNC(int) _PyXI_HasCapturedException(_PyXI_session *session);
262+
263+
136264
#ifdef __cplusplus
137265
}
138266
#endif

Include/internal/pycore_interp.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ struct _is {
153153
Py_ssize_t co_extra_user_count;
154154
freefunc co_extra_freefuncs[MAX_CO_EXTRA_USERS];
155155

156-
// XXX Remove this field once we have a tp_* slot.
157-
struct _xidregistry xidregistry;
156+
/* cross-interpreter data and utils */
157+
struct _xi_state xi;
158158

159159
#ifdef HAVE_FORK
160160
PyObject *before_forkers;

Include/internal/pycore_pyerrors.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,30 @@ extern PyStatus _PyErr_InitTypes(PyInterpreterState *);
6868
extern void _PyErr_FiniTypes(PyInterpreterState *);
6969

7070

71+
/* exception snapshots */
72+
73+
// Ultimately we'd like to preserve enough information about the
74+
// exception and traceback that we could re-constitute (or at least
75+
// simulate, a la traceback.TracebackException), and even chain, a copy
76+
// of the exception in the calling interpreter.
77+
78+
typedef struct _excinfo {
79+
const char *type;
80+
const char *msg;
81+
} _Py_excinfo;
82+
83+
extern void _Py_excinfo_Clear(_Py_excinfo *info);
84+
extern int _Py_excinfo_Copy(_Py_excinfo *dest, _Py_excinfo *src);
85+
extern const char * _Py_excinfo_InitFromException(
86+
_Py_excinfo *info,
87+
PyObject *exc);
88+
extern void _Py_excinfo_Apply(_Py_excinfo *info, PyObject *exctype);
89+
extern const char * _Py_excinfo_AsUTF8(
90+
_Py_excinfo *info,
91+
char *buf,
92+
size_t bufsize);
93+
94+
7195
/* other API */
7296

7397
static inline PyObject* _PyErr_Occurred(PyThreadState *tstate)

Include/internal/pycore_runtime.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,8 @@ typedef struct pyruntimestate {
200200
possible to facilitate out-of-process observability
201201
tools. */
202202

203-
// XXX Remove this field once we have a tp_* slot.
204-
struct _xidregistry xidregistry;
203+
/* cross-interpreter data and utils */
204+
struct _xi_runtime_state xi;
205205

206206
struct _pymem_allocators allocators;
207207
struct _obmalloc_global_state obmalloc;

Include/internal/pycore_runtime_init.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ extern PyTypeObject _PyExc_MemoryError;
9595
until _PyInterpreterState_Enable() is called. */ \
9696
.next_id = -1, \
9797
}, \
98+
.xi = { \
99+
.registry = { \
100+
.global = 1, \
101+
}, \
102+
}, \
98103
/* A TSS key must be initialized with Py_tss_NEEDS_INIT \
99104
in accordance with the specification. */ \
100105
.autoTSSkey = Py_tss_NEEDS_INIT, \

Lib/test/support/__init__.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2355,8 +2355,15 @@ def adjust_int_max_str_digits(max_digits):
23552355
#For recursion tests, easily exceeds default recursion limit
23562356
EXCEEDS_RECURSION_LIMIT = 5000
23572357

2358-
# The default C recursion limit (from Include/cpython/pystate.h).
2359-
Py_C_RECURSION_LIMIT = 1500
2358+
def _get_c_recursion_limit():
2359+
try:
2360+
import _testcapi
2361+
return _testcapi.Py_C_RECURSION_LIMIT
2362+
except (ImportError, AttributeError):
2363+
return 1500 # (from Include/cpython/pystate.h)
2364+
2365+
# The default C recursion limit.
2366+
Py_C_RECURSION_LIMIT = _get_c_recursion_limit()
23602367

23612368
#Windows doesn't have os.uname() but it doesn't support s390x.
23622369
skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == 's390x',

Lib/test/support/interpreters.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def close(self):
9292
return _interpreters.destroy(self._id)
9393

9494
# XXX Rename "run" to "exec"?
95-
def run(self, src_str, /, *, channels=None):
95+
def run(self, src_str, /, channels=None):
9696
"""Run the given source code in the interpreter.
9797
9898
This is essentially the same as calling the builtin "exec"

Lib/test/test__xxsubinterpreters.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ def test_default_shareables(self):
102102
'spam',
103103
10,
104104
-10,
105+
True,
106+
False,
105107
100.0,
106108
]
107109
for obj in shareables:
@@ -121,8 +123,6 @@ class SubBytes(bytes):
121123

122124
not_shareables = [
123125
# singletons
124-
True,
125-
False,
126126
NotImplemented,
127127
...,
128128
# builtin types and objects
@@ -189,6 +189,9 @@ def test_non_shareable_int(self):
189189
with self.assertRaises(OverflowError):
190190
_testinternalcapi.get_crossinterp_data(i)
191191

192+
def test_bool(self):
193+
self._assert_values([True, False])
194+
192195
def test_float(self):
193196
self._assert_values([0.0, 1.1, -1.0, 0.12345678, -0.12345678])
194197

0 commit comments

Comments
 (0)