Skip to content

Commit 38a83d6

Browse files
authored
Merge branch 'main' into fix-gh-132962-win-repl-redirect
2 parents 36eb0f8 + eed827e commit 38a83d6

Some content is hidden

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

63 files changed

+979
-388
lines changed

.github/CODEOWNERS

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,13 @@ Doc/howto/clinic.rst @erlend-aasland
281281
# Subinterpreters
282282
**/*interpreteridobject.* @ericsnowcurrently
283283
**/*crossinterp* @ericsnowcurrently
284-
Lib/test/support/interpreters/ @ericsnowcurrently
285284
Modules/_interp*module.c @ericsnowcurrently
285+
Lib/test/test__interp*.py @ericsnowcurrently
286+
Lib/concurrent/interpreters/ @ericsnowcurrently
287+
Lib/test/support/channels.py @ericsnowcurrently
288+
Doc/library/concurrent.interpreters.rst @ericsnowcurrently
286289
Lib/test/test_interpreters/ @ericsnowcurrently
290+
Lib/concurrent/futures/interpreter.py @ericsnowcurrently
287291

288292
# Android
289293
**/*Android* @mhsmith @freakboy3742

Doc/c-api/init.rst

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -492,17 +492,8 @@ Initializing and finalizing the interpreter
492492
strings other than those passed in (however, the contents of the strings
493493
pointed to by the argument list are not modified).
494494
495-
The return value will be ``0`` if the interpreter exits normally (i.e.,
496-
without an exception), ``1`` if the interpreter exits due to an exception,
497-
or ``2`` if the argument list does not represent a valid Python command
498-
line.
499-
500-
Note that if an otherwise unhandled :exc:`SystemExit` is raised, this
501-
function will not return ``1``, but exit the process, as long as
502-
``Py_InspectFlag`` is not set. If ``Py_InspectFlag`` is set, execution will
503-
drop into the interactive Python prompt, at which point a second otherwise
504-
unhandled :exc:`SystemExit` will still exit the process, while any other
505-
means of exiting will set the return value as described above.
495+
The return value is ``2`` if the argument list does not represent a valid
496+
Python command line, and otherwise the same as :c:func:`Py_RunMain`.
506497
507498
In terms of the CPython runtime configuration APIs documented in the
508499
:ref:`runtime configuration <init-config>` section (and without accounting
@@ -539,23 +530,18 @@ Initializing and finalizing the interpreter
539530
540531
If :c:member:`PyConfig.inspect` is not set (the default), the return value
541532
will be ``0`` if the interpreter exits normally (that is, without raising
542-
an exception), or ``1`` if the interpreter exits due to an exception. If an
543-
otherwise unhandled :exc:`SystemExit` is raised, the function will immediately
544-
exit the process instead of returning ``1``.
533+
an exception), the exit status of an unhandled :exc:`SystemExit`, or ``1``
534+
for any other unhandled exception.
545535
546536
If :c:member:`PyConfig.inspect` is set (such as when the :option:`-i` option
547537
is used), rather than returning when the interpreter exits, execution will
548538
instead resume in an interactive Python prompt (REPL) using the ``__main__``
549539
module's global namespace. If the interpreter exited with an exception, it
550540
is immediately raised in the REPL session. The function return value is
551-
then determined by the way the *REPL session* terminates: returning ``0``
552-
if the session terminates without raising an unhandled exception, exiting
553-
immediately for an unhandled :exc:`SystemExit`, and returning ``1`` for
554-
any other unhandled exception.
555-
556-
This function always finalizes the Python interpreter regardless of whether
557-
it returns a value or immediately exits the process due to an unhandled
558-
:exc:`SystemExit` exception.
541+
then determined by the way the *REPL session* terminates: ``0``, ``1``, or
542+
the status of a :exc:`SystemExit`, as specified above.
543+
544+
This function always finalizes the Python interpreter before it returns.
559545
560546
See :ref:`Python Configuration <init-python-config>` for an example of a
561547
customized Python that always runs in isolated mode using

Doc/library/concurrency.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ multitasking). Here's an overview:
1818
multiprocessing.shared_memory.rst
1919
concurrent.rst
2020
concurrent.futures.rst
21+
concurrent.interpreters.rst
2122
subprocess.rst
2223
sched.rst
2324
queue.rst
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
:mod:`!concurrent.interpreters` --- Multiple interpreters in the same process
2+
=============================================================================
3+
4+
.. module:: concurrent.interpreters
5+
:synopsis: Multiple interpreters in the same process
6+
7+
.. moduleauthor:: Eric Snow <[email protected]>
8+
.. sectionauthor:: Eric Snow <[email protected]>
9+
10+
.. versionadded:: 3.14
11+
12+
**Source code:** :source:`Lib/concurrent/interpreters.py`
13+
14+
--------------
15+
16+
17+
Introduction
18+
------------
19+
20+
The :mod:`!concurrent.interpreters` module constructs higher-level
21+
interfaces on top of the lower level :mod:`!_interpreters` module.
22+
23+
.. XXX Add references to the upcoming HOWTO docs in the seealso block.
24+
25+
.. seealso::
26+
27+
:ref:`isolating-extensions-howto`
28+
how to update an extension module to support multiple interpreters
29+
30+
:pep:`554`
31+
32+
:pep:`734`
33+
34+
:pep:`684`
35+
36+
.. XXX Why do we disallow multiple interpreters on WASM?
37+
38+
.. include:: ../includes/wasm-notavail.rst
39+
40+
41+
Key details
42+
-----------
43+
44+
Before we dive into examples, there are a small number of details
45+
to keep in mind about using multiple interpreters:
46+
47+
* isolated, by default
48+
* no implicit threads
49+
* not all PyPI packages support use in multiple interpreters yet
50+
51+
.. XXX Are there other relevant details to list?
52+
53+
In the context of multiple interpreters, "isolated" means that
54+
different interpreters do not share any state. In practice, there is some
55+
process-global data they all share, but that is managed by the runtime.
56+
57+
58+
Reference
59+
---------
60+
61+
This module defines the following functions:
62+
63+
.. function:: list_all()
64+
65+
Return a :class:`list` of :class:`Interpreter` objects,
66+
one for each existing interpreter.
67+
68+
.. function:: get_current()
69+
70+
Return an :class:`Interpreter` object for the currently running
71+
interpreter.
72+
73+
.. function:: get_main()
74+
75+
Return an :class:`Interpreter` object for the main interpreter.
76+
77+
.. function:: create()
78+
79+
Initialize a new (idle) Python interpreter
80+
and return a :class:`Interpreter` object for it.
81+
82+
83+
Interpreter objects
84+
^^^^^^^^^^^^^^^^^^^
85+
86+
.. class:: Interpreter(id)
87+
88+
A single interpreter in the current process.
89+
90+
Generally, :class:`Interpreter` shouldn't be called directly.
91+
Instead, use :func:`create` or one of the other module functions.
92+
93+
.. attribute:: id
94+
95+
(read-only)
96+
97+
The interpreter's ID.
98+
99+
.. attribute:: whence
100+
101+
(read-only)
102+
103+
A string describing where the interpreter came from.
104+
105+
.. method:: is_running()
106+
107+
Return ``True`` if the interpreter is currently executing code
108+
in its :mod:`!__main__` module and ``False`` otherwise.
109+
110+
.. method:: close()
111+
112+
Finalize and destroy the interpreter.
113+
114+
.. method:: prepare_main(ns=None, **kwargs)
115+
116+
Bind "shareable" objects in the interpreter's
117+
:mod:`!__main__` module.
118+
119+
.. method:: exec(code, /, dedent=True)
120+
121+
Run the given source code in the interpreter (in the current thread).
122+
123+
.. method:: call(callable, /, *args, **kwargs)
124+
125+
Return the result of calling running the given function in the
126+
interpreter (in the current thread).
127+
128+
.. method:: call_in_thread(callable, /, *args, **kwargs)
129+
130+
Run the given function in the interpreter (in a new thread).
131+
132+
Exceptions
133+
^^^^^^^^^^
134+
135+
.. exception:: InterpreterError
136+
137+
This exception, a subclass of :exc:`Exception`, is raised when
138+
an interpreter-related error happens.
139+
140+
.. exception:: InterpreterNotFoundError
141+
142+
This exception, a subclass of :exc:`InterpreterError`, is raised when
143+
the targeted interpreter no longer exists.
144+
145+
.. exception:: ExecutionFailed
146+
147+
This exception, a subclass of :exc:`InterpreterError`, is raised when
148+
the running code raised an uncaught exception.
149+
150+
.. attribute:: excinfo
151+
152+
A basic snapshot of the exception raised in the other interpreter.
153+
154+
.. XXX Document the excinfoattrs?
155+
156+
.. exception:: NotShareableError
157+
158+
This exception, a subclass of :exc:`TypeError`, is raised when
159+
an object cannot be sent to another interpreter.
160+
161+
162+
.. XXX Add functions for communicating between interpreters.
163+
164+
165+
Basic usage
166+
-----------
167+
168+
Creating an interpreter and running code in it::
169+
170+
from concurrent import interpreters
171+
172+
interp = interpreters.create()
173+
174+
# Run in the current OS thread.
175+
176+
interp.exec('print("spam!")')
177+
178+
interp.exec("""if True:
179+
print('spam!')
180+
""")
181+
182+
from textwrap import dedent
183+
interp.exec(dedent("""
184+
print('spam!')
185+
"""))
186+
187+
def run():
188+
print('spam!')
189+
190+
interp.call(run)
191+
192+
# Run in new OS thread.
193+
194+
t = interp.call_in_thread(run)
195+
t.join()
196+
197+
198+
.. XXX Explain about object "sharing".

Doc/library/concurrent.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
The :mod:`!concurrent` package
22
==============================
33

4-
Currently, there is only one module in this package:
4+
This package contains the following modules:
55

66
* :mod:`concurrent.futures` -- Launching parallel tasks
7+
* :mod:`concurrent.interpreters` -- Multiple interpreters in the same process

Doc/library/dataclasses.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,11 @@ Module contents
121121
:meth:`!__le__`, :meth:`!__gt__`, or :meth:`!__ge__`, then
122122
:exc:`TypeError` is raised.
123123

124-
- *unsafe_hash*: If ``False`` (the default), a :meth:`~object.__hash__` method
125-
is generated according to how *eq* and *frozen* are set.
124+
- *unsafe_hash*: If true, force ``dataclasses`` to create a
125+
:meth:`~object.__hash__` method, even though it may not be safe to do so.
126+
Otherwise, generate a :meth:`~object.__hash__` method according to how
127+
*eq* and *frozen* are set.
128+
The default value is ``False``.
126129

127130
:meth:`!__hash__` is used by built-in :meth:`hash`, and when objects are
128131
added to hashed collections such as dictionaries and sets. Having a

Doc/library/logging.config.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ mnemonic that the corresponding value is a callable.
548548
The ``filters`` member of ``handlers`` and ``loggers`` can take
549549
filter instances in addition to ids.
550550

551-
You can also specify a special key ``'.'`` whose value is a dictionary is a
551+
You can also specify a special key ``'.'`` whose value is a
552552
mapping of attribute names to values. If found, the specified attributes will
553553
be set on the user-defined object before it is returned. Thus, with the
554554
following configuration::

Doc/library/math.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,8 @@ Floating point manipulation functions
387387
.. function:: issubnormal(x)
388388

389389
Return ``True`` if *x* is a subnormal number, that is a finite
390-
nonzero number with a magnitude smaller than the smallest positive normal
391-
number, see :data:`sys.float_info.min`. Return ``False`` otherwise.
390+
nonzero number with a magnitude smaller than :data:`sys.float_info.min`.
391+
Return ``False`` otherwise.
392392

393393
.. versionadded:: next
394394

Doc/library/python.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,8 @@ overview:
2727
inspect.rst
2828
annotationlib.rst
2929
site.rst
30+
31+
.. seealso::
32+
33+
* See the :mod:`concurrent.interpreters` module, which similarly
34+
exposes core runtime functionality.

Doc/library/stdtypes.rst

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1841,6 +1841,14 @@ expression support in the :mod:`re` module).
18411841
unless an encoding error actually occurs,
18421842
:ref:`devmode` is enabled
18431843
or a :ref:`debug build <debug-build>` is used.
1844+
For example::
1845+
1846+
>>> encoded_str_to_bytes = 'Python'.encode()
1847+
>>> type(encoded_str_to_bytes)
1848+
<class 'bytes'>
1849+
>>> encoded_str_to_bytes
1850+
b'Python'
1851+
18441852

18451853
.. versionchanged:: 3.1
18461854
Added support for keyword arguments.
@@ -1855,7 +1863,19 @@ expression support in the :mod:`re` module).
18551863
Return ``True`` if the string ends with the specified *suffix*, otherwise return
18561864
``False``. *suffix* can also be a tuple of suffixes to look for. With optional
18571865
*start*, test beginning at that position. With optional *end*, stop comparing
1858-
at that position.
1866+
at that position. Using *start* and *end* is equivalent to
1867+
``str[start:end].endswith(suffix)``. For example::
1868+
1869+
>>> 'Python'.endswith('on')
1870+
True
1871+
>>> 'a tuple of suffixes'.endswith(('at', 'in'))
1872+
False
1873+
>>> 'a tuple of suffixes'.endswith(('at', 'es'))
1874+
True
1875+
>>> 'Python is amazing'.endswith('is', 0, 9)
1876+
True
1877+
1878+
See also :meth:`startswith` and :meth:`removesuffix`.
18591879

18601880

18611881
.. method:: str.expandtabs(tabsize=8)

0 commit comments

Comments
 (0)