Skip to content

Commit bf6f3aa

Browse files
authored
Merge branch 'main' into issue-99631-2
2 parents 34a32b9 + 1a89991 commit bf6f3aa

20 files changed

Lines changed: 1375 additions & 332 deletions

File tree

Doc/c-api/module.rst

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -288,22 +288,40 @@ An alternate way to specify extensions is to request "multi-phase initialization
288288
Extension modules created this way behave more like Python modules: the
289289
initialization is split between the *creation phase*, when the module object
290290
is created, and the *execution phase*, when it is populated.
291-
The distinction is similar to the :py:meth:`!__new__` and :py:meth:`!__init__` methods
292-
of classes.
291+
The distinction is similar to the :py:meth:`~object.__new__` and
292+
:py:meth:`~object.__init__` methods of classes.
293293
294294
Unlike modules created using single-phase initialization, these modules are not
295-
singletons: if the *sys.modules* entry is removed and the module is re-imported,
296-
a new module object is created, and the old module is subject to normal garbage
297-
collection -- as with Python modules.
298-
By default, multiple modules created from the same definition should be
299-
independent: changes to one should not affect the others.
300-
This means that all state should be specific to the module object (using e.g.
301-
using :c:func:`PyModule_GetState`), or its contents (such as the module's
302-
:attr:`~object.__dict__` or individual classes created with :c:func:`PyType_FromSpec`).
295+
singletons.
296+
For example, if the :py:attr:`sys.modules` entry is removed and the module
297+
is re-imported, a new module object is created, and typically populated with
298+
fresh method and type objects.
299+
The old module is subject to normal garbage collection.
300+
This mirrors the behavior of pure-Python modules.
301+
302+
Additional module instances may be created in
303+
:ref:`sub-interpreters <sub-interpreter-support>`
304+
or after after Python runtime reinitialization
305+
(:c:func:`Py_Finalize` and :c:func:`Py_Initialize`).
306+
In these cases, sharing Python objects between module instances would likely
307+
cause crashes or undefined behavior.
308+
309+
To avoid such issues, each instance of an extension module should
310+
be *isolated*: changes to one instance should not implicitly affect the others,
311+
and all state, including references to Python objects, should be specific to
312+
a particular module instance.
313+
See :ref:`isolating-extensions-howto` for more details and a practical guide.
314+
315+
A simpler way to avoid these issues is
316+
:ref:`raising an error on repeated initialization <isolating-extensions-optout>`.
303317
304318
All modules created using multi-phase initialization are expected to support
305-
:ref:`sub-interpreters <sub-interpreter-support>`. Making sure multiple modules
306-
are independent is typically enough to achieve this.
319+
:ref:`sub-interpreters <sub-interpreter-support>`, or otherwise explicitly
320+
signal a lack of support.
321+
This is usually achieved by isolation or blocking repeated initialization,
322+
as above.
323+
A module may also be limited to the main interpreter using
324+
the :c:data:`Py_mod_multiple_interpreters` slot.
307325
308326
To request multi-phase initialization, the initialization function
309327
(PyInit_modulename) returns a :c:type:`PyModuleDef` instance with non-empty

Doc/howto/isolating-extensions.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ possible, consider explicit locking.
168168
If it is necessary to use process-global state, the simplest way to
169169
avoid issues with multiple interpreters is to explicitly prevent a
170170
module from being loaded more than once per process—see
171-
`Opt-Out: Limiting to One Module Object per Process`_.
171+
:ref:`isolating-extensions-optout`.
172172

173173

174174
Managing Per-Module State
@@ -207,6 +207,8 @@ An example of a module with per-module state is currently available as
207207
example module initialization shown at the bottom of the file.
208208

209209

210+
.. _isolating-extensions-optout:
211+
210212
Opt-Out: Limiting to One Module Object per Process
211213
--------------------------------------------------
212214

Doc/library/ast.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2445,8 +2445,9 @@ and classes for traversing abstract syntax trees:
24452445
indents that many spaces per level. If *indent* is a string (such as ``"\t"``),
24462446
that string is used to indent each level.
24472447

2448-
If *show_empty* is ``False`` (the default), empty lists and fields that are ``None``
2449-
will be omitted from the output.
2448+
If *show_empty* is false (the default), optional empty lists will be
2449+
omitted from the output.
2450+
Optional ``None`` values are always omitted.
24502451

24512452
.. versionchanged:: 3.9
24522453
Added the *indent* option.

Include/internal/mimalloc/mimalloc/types.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,32 @@ terms of the MIT license. A copy of the license can be found in the file
5050
#define mi_decl_cache_align
5151
#endif
5252

53+
#if (MI_DEBUG)
54+
#if defined(_MSC_VER)
55+
#define mi_decl_noreturn __declspec(noreturn)
56+
#elif (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__)
57+
#define mi_decl_noreturn __attribute__((__noreturn__))
58+
#else
59+
#define mi_decl_noreturn
60+
#endif
61+
62+
/*
63+
* 'cold' attribute seems to have been fully supported since GCC 4.x.
64+
* See https://github.com/gcc-mirror/gcc/commit/52bf96d2f299e9e6.
65+
*/
66+
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
67+
#define mi_decl_cold __attribute__((cold))
68+
#else
69+
#define mi_decl_cold
70+
#endif
71+
72+
#if (defined(__GNUC__) && defined(__THROW))
73+
#define mi_decl_throw __THROW
74+
#else
75+
#define mi_decl_throw
76+
#endif
77+
#endif
78+
5379
// ------------------------------------------------------
5480
// Variants
5581
// ------------------------------------------------------
@@ -582,7 +608,8 @@ struct mi_heap_s {
582608

583609
#if (MI_DEBUG)
584610
// use our own assertion to print without memory allocation
585-
void _mi_assert_fail(const char* assertion, const char* fname, unsigned int line, const char* func );
611+
mi_decl_noreturn mi_decl_cold mi_decl_throw
612+
void _mi_assert_fail(const char* assertion, const char* fname, unsigned int line, const char* func);
586613
#define mi_assert(expr) ((expr) ? (void)0 : _mi_assert_fail(#expr,__FILE__,__LINE__,__func__))
587614
#else
588615
#define mi_assert(x)

Include/internal/pycore_crossinterp.h

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,9 @@ typedef enum error_code {
317317
_PyXI_ERR_ALREADY_RUNNING = -4,
318318
_PyXI_ERR_MAIN_NS_FAILURE = -5,
319319
_PyXI_ERR_APPLY_NS_FAILURE = -6,
320-
_PyXI_ERR_NOT_SHAREABLE = -7,
320+
_PyXI_ERR_PRESERVE_FAILURE = -7,
321+
_PyXI_ERR_EXC_PROPAGATION_FAILURE = -8,
322+
_PyXI_ERR_NOT_SHAREABLE = -9,
321323
} _PyXI_errcode;
322324

323325

@@ -350,16 +352,33 @@ typedef struct xi_session _PyXI_session;
350352
PyAPI_FUNC(_PyXI_session *) _PyXI_NewSession(void);
351353
PyAPI_FUNC(void) _PyXI_FreeSession(_PyXI_session *);
352354

355+
typedef struct {
356+
PyObject *preserved;
357+
PyObject *excinfo;
358+
_PyXI_errcode errcode;
359+
} _PyXI_session_result;
360+
PyAPI_FUNC(void) _PyXI_ClearResult(_PyXI_session_result *);
361+
353362
PyAPI_FUNC(int) _PyXI_Enter(
354363
_PyXI_session *session,
355364
PyInterpreterState *interp,
356-
PyObject *nsupdates);
357-
PyAPI_FUNC(void) _PyXI_Exit(_PyXI_session *session);
358-
359-
PyAPI_FUNC(PyObject *) _PyXI_GetMainNamespace(_PyXI_session *);
360-
361-
PyAPI_FUNC(PyObject *) _PyXI_ApplyCapturedException(_PyXI_session *session);
362-
PyAPI_FUNC(int) _PyXI_HasCapturedException(_PyXI_session *session);
365+
PyObject *nsupdates,
366+
_PyXI_session_result *);
367+
PyAPI_FUNC(int) _PyXI_Exit(
368+
_PyXI_session *,
369+
_PyXI_errcode,
370+
_PyXI_session_result *);
371+
372+
PyAPI_FUNC(PyObject *) _PyXI_GetMainNamespace(
373+
_PyXI_session *,
374+
_PyXI_errcode *);
375+
376+
PyAPI_FUNC(int) _PyXI_Preserve(
377+
_PyXI_session *,
378+
const char *,
379+
PyObject *,
380+
_PyXI_errcode *);
381+
PyAPI_FUNC(PyObject *) _PyXI_GetPreserved(_PyXI_session_result *, const char *);
363382

364383

365384
/*************/

Lib/ast.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -147,18 +147,16 @@ def _format(node, level=0):
147147
if value is None and getattr(cls, name, ...) is None:
148148
keywords = True
149149
continue
150-
if (
151-
not show_empty
152-
and (value is None or value == [])
153-
# Special cases:
154-
# `Constant(value=None)` and `MatchSingleton(value=None)`
155-
and not isinstance(node, (Constant, MatchSingleton))
156-
):
157-
args_buffer.append(repr(value))
158-
continue
159-
elif not keywords:
160-
args.extend(args_buffer)
161-
args_buffer = []
150+
if not show_empty:
151+
if value == []:
152+
field_type = cls._field_types.get(name, object)
153+
if getattr(field_type, '__origin__', ...) is list:
154+
if not keywords:
155+
args_buffer.append(repr(value))
156+
continue
157+
if not keywords:
158+
args.extend(args_buffer)
159+
args_buffer = []
162160
value, simple = _format(value, level)
163161
allsimple = allsimple and simple
164162
if keywords:

Lib/test/_code_definitions.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ def spam_with_globals_and_builtins():
5757
print(res)
5858

5959

60+
def spam_full_args(a, b, /, c, d, *args, e, f, **kwargs):
61+
return (a, b, c, d, e, f, args, kwargs)
62+
63+
64+
def spam_full_args_with_defaults(a=-1, b=-2, /, c=-3, d=-4, *args,
65+
e=-5, f=-6, **kwargs):
66+
return (a, b, c, d, e, f, args, kwargs)
67+
68+
6069
def spam_args_attrs_and_builtins(a, b, /, c, d, *args, e, f, **kwargs):
6170
if args.__len__() > 2:
6271
return None
@@ -67,6 +76,10 @@ def spam_returns_arg(x):
6776
return x
6877

6978

79+
def spam_raises():
80+
raise Exception('spam!')
81+
82+
7083
def spam_with_inner_not_closure():
7184
def eggs():
7285
pass
@@ -177,8 +190,11 @@ def ham_C_closure(z):
177190
spam_minimal,
178191
spam_with_builtins,
179192
spam_with_globals_and_builtins,
193+
spam_full_args,
194+
spam_full_args_with_defaults,
180195
spam_args_attrs_and_builtins,
181196
spam_returns_arg,
197+
spam_raises,
182198
spam_with_inner_not_closure,
183199
spam_with_inner_closure,
184200
spam_annotated,
@@ -219,8 +235,10 @@ def ham_C_closure(z):
219235
spam,
220236
spam_minimal,
221237
spam_with_builtins,
238+
spam_full_args,
222239
spam_args_attrs_and_builtins,
223240
spam_returns_arg,
241+
spam_raises,
224242
spam_annotated,
225243
spam_with_inner_not_closure,
226244
spam_with_inner_closure,
@@ -238,6 +256,7 @@ def ham_C_closure(z):
238256
STATELESS_CODE = [
239257
*STATELESS_FUNCTIONS,
240258
script_with_globals,
259+
spam_full_args_with_defaults,
241260
spam_with_globals_and_builtins,
242261
spam_full,
243262
]
@@ -248,6 +267,7 @@ def ham_C_closure(z):
248267
script_with_explicit_empty_return,
249268
spam_minimal,
250269
spam_with_builtins,
270+
spam_raises,
251271
spam_with_inner_not_closure,
252272
spam_with_inner_closure,
253273
]

Lib/test/support/interpreters/__init__.py

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -226,33 +226,32 @@ def exec(self, code, /):
226226
if excinfo is not None:
227227
raise ExecutionFailed(excinfo)
228228

229-
def call(self, callable, /):
230-
"""Call the object in the interpreter with given args/kwargs.
229+
def _call(self, callable, args, kwargs):
230+
res, excinfo = _interpreters.call(self._id, callable, args, kwargs, restrict=True)
231+
if excinfo is not None:
232+
raise ExecutionFailed(excinfo)
233+
return res
231234

232-
Only functions that take no arguments and have no closure
233-
are supported.
235+
def call(self, callable, /, *args, **kwargs):
236+
"""Call the object in the interpreter with given args/kwargs.
234237
235-
The return value is discarded.
238+
Nearly all callables, args, kwargs, and return values are
239+
supported. All "shareable" objects are supported, as are
240+
"stateless" functions (meaning non-closures that do not use
241+
any globals). This method will fall back to pickle.
236242
237243
If the callable raises an exception then the error display
238-
(including full traceback) is send back between the interpreters
244+
(including full traceback) is sent back between the interpreters
239245
and an ExecutionFailed exception is raised, much like what
240246
happens with Interpreter.exec().
241247
"""
242-
# XXX Support args and kwargs.
243-
# XXX Support arbitrary callables.
244-
# XXX Support returning the return value (e.g. via pickle).
245-
excinfo = _interpreters.call(self._id, callable, restrict=True)
246-
if excinfo is not None:
247-
raise ExecutionFailed(excinfo)
248+
return self._call(callable, args, kwargs)
248249

249-
def call_in_thread(self, callable, /):
250+
def call_in_thread(self, callable, /, *args, **kwargs):
250251
"""Return a new thread that calls the object in the interpreter.
251252
252253
The return value and any raised exception are discarded.
253254
"""
254-
def task():
255-
self.call(callable)
256-
t = threading.Thread(target=task)
255+
t = threading.Thread(target=self._call, args=(callable, args, kwargs))
257256
t.start()
258257
return t

Lib/test/test_ast/test_ast.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,18 +1543,42 @@ def check_text(code, empty, full, **kwargs):
15431543
full="MatchSingleton(value=None)",
15441544
)
15451545

1546+
check_node(
1547+
ast.MatchSingleton(value=[]),
1548+
empty="MatchSingleton(value=[])",
1549+
full="MatchSingleton(value=[])",
1550+
)
1551+
15461552
check_node(
15471553
ast.Constant(value=None),
15481554
empty="Constant(value=None)",
15491555
full="Constant(value=None)",
15501556
)
15511557

1558+
check_node(
1559+
ast.Constant(value=[]),
1560+
empty="Constant(value=[])",
1561+
full="Constant(value=[])",
1562+
)
1563+
15521564
check_node(
15531565
ast.Constant(value=''),
15541566
empty="Constant(value='')",
15551567
full="Constant(value='')",
15561568
)
15571569

1570+
check_node(
1571+
ast.Interpolation(value=ast.Constant(42), str=None, conversion=-1),
1572+
empty="Interpolation(value=Constant(value=42), str=None, conversion=-1)",
1573+
full="Interpolation(value=Constant(value=42), str=None, conversion=-1)",
1574+
)
1575+
1576+
check_node(
1577+
ast.Interpolation(value=ast.Constant(42), str=[], conversion=-1),
1578+
empty="Interpolation(value=Constant(value=42), str=[], conversion=-1)",
1579+
full="Interpolation(value=Constant(value=42), str=[], conversion=-1)",
1580+
)
1581+
15581582
check_text(
15591583
"def a(b: int = 0, *, c): ...",
15601584
empty="Module(body=[FunctionDef(name='a', args=arguments(args=[arg(arg='b', annotation=Name(id='int', ctx=Load()))], kwonlyargs=[arg(arg='c')], kw_defaults=[None], defaults=[Constant(value=0)]), body=[Expr(value=Constant(value=Ellipsis))])])",

0 commit comments

Comments
 (0)