-
-
Notifications
You must be signed in to change notification settings - Fork 32k
gh-76785: Fixes for test.support.interpreters #112982
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
ericsnowcurrently
merged 26 commits into
python:main
from
ericsnowcurrently:pep-734-updates
Dec 12, 2023
Merged
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
76a7d7b
Make Interpreter() idempotent.
ericsnowcurrently 57a3c19
Interpreters are always isolated.
ericsnowcurrently 747e542
interp.id is always int.
ericsnowcurrently 0ed9fb0
Add InterpreterNotFoundError.
ericsnowcurrently 98f9cf3
Stop using InterpreterID in _interpreters.
ericsnowcurrently 0277878
Fix Interpreter.__repr__().
ericsnowcurrently 59c8227
.run() -> .exec_sync()
ericsnowcurrently fa132a2
RunFailedError -> ExecFailure
ericsnowcurrently 644efa5
Add Interpreter.run().
ericsnowcurrently abf2aa8
Make the interpreters module a package.
ericsnowcurrently 8ca303f
Add interpreters.Queue.
ericsnowcurrently 8b97373
Add memoryview XID with _xxsubinterpreters import.
ericsnowcurrently cc20f1f
Update CODEOWNERS.
ericsnowcurrently cb0a605
Ignore static builtin exception types.
ericsnowcurrently 62a9bac
Make CODEOWNERS more specific.
ericsnowcurrently 6c71018
Fix submodule names.
ericsnowcurrently 13a44e3
Use interpreters.__getattr__() for submodule aliases.
ericsnowcurrently c9d15d2
Fix InterpreterIDTests.
ericsnowcurrently 1c76c4a
LONG_LONG_MAX -> LLONG_MAX
ericsnowcurrently cfae15f
Fix Interpreter.run().
ericsnowcurrently 3f98ce1
Use exec_sync() in test_sys.
ericsnowcurrently f8b1685
Fix test_capi.
ericsnowcurrently 0b34a83
Fix test_importlib.
ericsnowcurrently 68faf1a
Fix test_import.
ericsnowcurrently d161f76
Fix test_threading.
ericsnowcurrently 778276f
Fix TestInterpreterRun.
ericsnowcurrently File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
"""Subinterpreters High Level Module.""" | ||
|
||
import threading | ||
import weakref | ||
import _xxsubinterpreters as _interpreters | ||
|
||
# aliases: | ||
from _xxsubinterpreters import ( | ||
InterpreterError, InterpreterNotFoundError, | ||
is_shareable, | ||
) | ||
|
||
|
||
__all__ = [ | ||
'get_current', 'get_main', 'create', 'list_all', 'is_shareable', | ||
'Interpreter', | ||
'InterpreterError', 'InterpreterNotFoundError', 'ExecFailure', | ||
'create_queue', 'Queue', 'QueueEmpty', 'QueueFull', | ||
] | ||
|
||
|
||
_queuemod = None | ||
|
||
def __getattr__(name): | ||
if name in ('Queue', 'QueueEmpty', 'QueueFull', 'create_queue'): | ||
global create_queue, Queue, QueueEmpty, QueueFull | ||
ns = globals() | ||
from .queues import ( | ||
create as create_queue, | ||
Queue, QueueEmpty, QueueFull, | ||
) | ||
return ns[name] | ||
else: | ||
raise AttributeError(name) | ||
|
||
|
||
class ExecFailure(RuntimeError): | ||
|
||
def __init__(self, excinfo): | ||
msg = excinfo.formatted | ||
if not msg: | ||
if excinfo.type and snapshot.msg: | ||
msg = f'{snapshot.type.__name__}: {snapshot.msg}' | ||
else: | ||
msg = snapshot.type.__name__ or snapshot.msg | ||
super().__init__(msg) | ||
self.snapshot = excinfo | ||
|
||
|
||
def create(): | ||
"""Return a new (idle) Python interpreter.""" | ||
id = _interpreters.create(isolated=True) | ||
return Interpreter(id) | ||
|
||
|
||
def list_all(): | ||
"""Return all existing interpreters.""" | ||
return [Interpreter(id) for id in _interpreters.list_all()] | ||
|
||
|
||
def get_current(): | ||
"""Return the currently running interpreter.""" | ||
id = _interpreters.get_current() | ||
return Interpreter(id) | ||
|
||
|
||
def get_main(): | ||
"""Return the main interpreter.""" | ||
id = _interpreters.get_main() | ||
return Interpreter(id) | ||
|
||
|
||
_known = weakref.WeakValueDictionary() | ||
|
||
class Interpreter: | ||
"""A single Python interpreter.""" | ||
|
||
def __new__(cls, id, /): | ||
# There is only one instance for any given ID. | ||
if not isinstance(id, int): | ||
raise TypeError(f'id must be an int, got {id!r}') | ||
id = int(id) | ||
try: | ||
self = _known[id] | ||
assert hasattr(self, '_ownsref') | ||
except KeyError: | ||
# This may raise InterpreterNotFoundError: | ||
_interpreters._incref(id) | ||
try: | ||
self = super().__new__(cls) | ||
self._id = id | ||
self._ownsref = True | ||
except BaseException: | ||
_interpreters._deccref(id) | ||
raise | ||
_known[id] = self | ||
return self | ||
|
||
def __repr__(self): | ||
return f'{type(self).__name__}({self.id})' | ||
|
||
def __hash__(self): | ||
return hash(self._id) | ||
|
||
def __del__(self): | ||
self._decref() | ||
|
||
def _decref(self): | ||
if not self._ownsref: | ||
return | ||
self._ownsref = False | ||
try: | ||
_interpreters._decref(self.id) | ||
except InterpreterNotFoundError: | ||
pass | ||
|
||
@property | ||
def id(self): | ||
return self._id | ||
|
||
def is_running(self): | ||
"""Return whether or not the identified interpreter is running.""" | ||
return _interpreters.is_running(self._id) | ||
|
||
def close(self): | ||
"""Finalize and destroy the interpreter. | ||
|
||
Attempting to destroy the current interpreter results | ||
in a RuntimeError. | ||
""" | ||
return _interpreters.destroy(self._id) | ||
|
||
def exec_sync(self, code, /, channels=None): | ||
"""Run the given source code in the interpreter. | ||
|
||
This is essentially the same as calling the builtin "exec" | ||
with this interpreter, using the __dict__ of its __main__ | ||
module as both globals and locals. | ||
|
||
There is no return value. | ||
|
||
If the code raises an unhandled exception then an ExecFailure | ||
is raised, which summarizes the unhandled exception. The actual | ||
exception is discarded because objects cannot be shared between | ||
interpreters. | ||
|
||
This blocks the current Python thread until done. During | ||
that time, the previous interpreter is allowed to run | ||
in other threads. | ||
""" | ||
excinfo = _interpreters.exec(self._id, code, channels) | ||
if excinfo is not None: | ||
raise ExecFailure(excinfo) | ||
|
||
def run(self, code, /, channels=None): | ||
def task(): | ||
self.exec_sync(code, channels=channels) | ||
t = threading.Thread(target=task) | ||
t.start() | ||
return t |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last matching pattern in
CODEOWNERS
takes the precedence, so you can do:to set @rhettinger as owner of all the
*queue*
files exceptsupport/interpreters/queues.py
, which will be owned by @ericsnowcurrently instead.Moving the subinterpreter section after the
**/*queue*
line should also override the owner forsupport/interpreters/queues.py
without further changes.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought there was something like that but I couldn't find it via web search. Thanks for explaining. I'll fix it in a follow-up PR.