Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit86a77f4

Browse files
gh-76785: Fixes for test.support.interpreters (gh-112982)
This involves a number of changes for PEP 734.
1 parentf26bfe4 commit86a77f4

30 files changed

+2506
-1507
lines changed

‎.github/CODEOWNERS‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ Python/traceback.c @iritkatriel
7878
**/*importlib/resources/*@jaraco@warsaw@FFY00
7979
**/importlib/metadata/*@jaraco@warsaw
8080

81+
# Subinterpreters
82+
Lib/test/support/interpreters/**@ericsnowcurrently
83+
Modules/_xx*interp*module.c@ericsnowcurrently
84+
Lib/test/test_interpreters/**@ericsnowcurrently
85+
8186
# Dates and times
8287
**/*datetime*@pganssle@abalkin
8388
**/*str*time*@pganssle@abalkin
@@ -148,7 +153,15 @@ Doc/c-api/stable.rst @encukou
148153
**/*itertools*@rhettinger
149154
**/*collections*@rhettinger
150155
**/*random*@rhettinger
151-
**/*queue*@rhettinger
156+
Doc/**/*queue*@rhettinger
157+
PCbuild/**/*queue*@rhettinger
158+
Modules/_queuemodule.c@rhettinger
159+
Lib/*queue*.py@rhettinger
160+
Lib/asyncio/*queue*.py@rhettinger
161+
Lib/multiprocessing/*queue*.py@rhettinger
162+
Lib/test/*queue*.py@rhettinger
163+
Lib/test_asyncio/*queue*.py@rhettinger
164+
Lib/test_multiprocessing/*queue*.py@rhettinger
152165
**/*bisect*@rhettinger
153166
**/*heapq*@rhettinger
154167
**/*functools*@rhettinger

‎Include/internal/pycore_crossinterp.h‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ extern "C" {
1111
#include"pycore_lock.h"// PyMutex
1212
#include"pycore_pyerrors.h"
1313

14+
/**************/
15+
/* exceptions */
16+
/**************/
17+
18+
PyAPI_DATA(PyObject*)PyExc_InterpreterError;
19+
PyAPI_DATA(PyObject*)PyExc_InterpreterNotFoundError;
20+
1421

1522
/***************************/
1623
/* cross-interpreter calls */
@@ -160,6 +167,9 @@ struct _xi_state {
160167
externPyStatus_PyXI_Init(PyInterpreterState*interp);
161168
externvoid_PyXI_Fini(PyInterpreterState*interp);
162169

170+
externPyStatus_PyXI_InitTypes(PyInterpreterState*interp);
171+
externvoid_PyXI_FiniTypes(PyInterpreterState*interp);
172+
163173

164174
/***************************/
165175
/* short-term data sharing */

‎Include/internal/pycore_interp.h‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,9 @@ _PyInterpreterState_SetFinalizing(PyInterpreterState *interp, PyThreadState *tst
250250
// Export for the _xxinterpchannels module.
251251
PyAPI_FUNC(PyInterpreterState*)_PyInterpreterState_LookUpID(int64_t);
252252

253-
externint_PyInterpreterState_IDInitref(PyInterpreterState*);
254-
externint_PyInterpreterState_IDIncref(PyInterpreterState*);
255-
externvoid_PyInterpreterState_IDDecref(PyInterpreterState*);
253+
PyAPI_FUNC(int)_PyInterpreterState_IDInitref(PyInterpreterState*);
254+
PyAPI_FUNC(int)_PyInterpreterState_IDIncref(PyInterpreterState*);
255+
PyAPI_FUNC(void)_PyInterpreterState_IDDecref(PyInterpreterState*);
256256

257257
externconstPyConfig*_PyInterpreterState_GetConfig(PyInterpreterState*interp);
258258

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
"""Subinterpreters High Level Module."""
2+
3+
importthreading
4+
importweakref
5+
import_xxsubinterpretersas_interpreters
6+
7+
# aliases:
8+
from_xxsubinterpretersimport (
9+
InterpreterError,InterpreterNotFoundError,
10+
is_shareable,
11+
)
12+
13+
14+
__all__= [
15+
'get_current','get_main','create','list_all','is_shareable',
16+
'Interpreter',
17+
'InterpreterError','InterpreterNotFoundError','ExecFailure',
18+
'create_queue','Queue','QueueEmpty','QueueFull',
19+
]
20+
21+
22+
_queuemod=None
23+
24+
def__getattr__(name):
25+
ifnamein ('Queue','QueueEmpty','QueueFull','create_queue'):
26+
globalcreate_queue,Queue,QueueEmpty,QueueFull
27+
ns=globals()
28+
from .queuesimport (
29+
createascreate_queue,
30+
Queue,QueueEmpty,QueueFull,
31+
)
32+
returnns[name]
33+
else:
34+
raiseAttributeError(name)
35+
36+
37+
classExecFailure(RuntimeError):
38+
39+
def__init__(self,excinfo):
40+
msg=excinfo.formatted
41+
ifnotmsg:
42+
ifexcinfo.typeandsnapshot.msg:
43+
msg=f'{snapshot.type.__name__}:{snapshot.msg}'
44+
else:
45+
msg=snapshot.type.__name__orsnapshot.msg
46+
super().__init__(msg)
47+
self.snapshot=excinfo
48+
49+
50+
defcreate():
51+
"""Return a new (idle) Python interpreter."""
52+
id=_interpreters.create(isolated=True)
53+
returnInterpreter(id)
54+
55+
56+
deflist_all():
57+
"""Return all existing interpreters."""
58+
return [Interpreter(id)foridin_interpreters.list_all()]
59+
60+
61+
defget_current():
62+
"""Return the currently running interpreter."""
63+
id=_interpreters.get_current()
64+
returnInterpreter(id)
65+
66+
67+
defget_main():
68+
"""Return the main interpreter."""
69+
id=_interpreters.get_main()
70+
returnInterpreter(id)
71+
72+
73+
_known=weakref.WeakValueDictionary()
74+
75+
classInterpreter:
76+
"""A single Python interpreter."""
77+
78+
def__new__(cls,id,/):
79+
# There is only one instance for any given ID.
80+
ifnotisinstance(id,int):
81+
raiseTypeError(f'id must be an int, got{id!r}')
82+
id=int(id)
83+
try:
84+
self=_known[id]
85+
asserthasattr(self,'_ownsref')
86+
exceptKeyError:
87+
# This may raise InterpreterNotFoundError:
88+
_interpreters._incref(id)
89+
try:
90+
self=super().__new__(cls)
91+
self._id=id
92+
self._ownsref=True
93+
exceptBaseException:
94+
_interpreters._deccref(id)
95+
raise
96+
_known[id]=self
97+
returnself
98+
99+
def__repr__(self):
100+
returnf'{type(self).__name__}({self.id})'
101+
102+
def__hash__(self):
103+
returnhash(self._id)
104+
105+
def__del__(self):
106+
self._decref()
107+
108+
def_decref(self):
109+
ifnotself._ownsref:
110+
return
111+
self._ownsref=False
112+
try:
113+
_interpreters._decref(self.id)
114+
exceptInterpreterNotFoundError:
115+
pass
116+
117+
@property
118+
defid(self):
119+
returnself._id
120+
121+
defis_running(self):
122+
"""Return whether or not the identified interpreter is running."""
123+
return_interpreters.is_running(self._id)
124+
125+
defclose(self):
126+
"""Finalize and destroy the interpreter.
127+
128+
Attempting to destroy the current interpreter results
129+
in a RuntimeError.
130+
"""
131+
return_interpreters.destroy(self._id)
132+
133+
defexec_sync(self,code,/,channels=None):
134+
"""Run the given source code in the interpreter.
135+
136+
This is essentially the same as calling the builtin "exec"
137+
with this interpreter, using the __dict__ of its __main__
138+
module as both globals and locals.
139+
140+
There is no return value.
141+
142+
If the code raises an unhandled exception then an ExecFailure
143+
is raised, which summarizes the unhandled exception. The actual
144+
exception is discarded because objects cannot be shared between
145+
interpreters.
146+
147+
This blocks the current Python thread until done. During
148+
that time, the previous interpreter is allowed to run
149+
in other threads.
150+
"""
151+
excinfo=_interpreters.exec(self._id,code,channels)
152+
ifexcinfoisnotNone:
153+
raiseExecFailure(excinfo)
154+
155+
defrun(self,code,/,channels=None):
156+
deftask():
157+
self.exec_sync(code,channels=channels)
158+
t=threading.Thread(target=task)
159+
t.start()
160+
returnt

‎Lib/test/support/interpreters.py‎renamed to ‎Lib/test/support/interpreters/channels.py‎

Lines changed: 6 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,135 +1,23 @@
1-
"""Subinterpreters High Level Module."""
1+
"""Cross-interpreter Channels High Level Module."""
22

33
importtime
4-
import_xxsubinterpretersas_interpreters
54
import_xxinterpchannelsas_channels
65

76
# aliases:
8-
from_xxsubinterpretersimportis_shareable
97
from_xxinterpchannelsimport (
108
ChannelError,ChannelNotFoundError,ChannelClosedError,
119
ChannelEmptyError,ChannelNotEmptyError,
1210
)
1311

1412

1513
__all__= [
16-
'Interpreter','get_current','get_main','create','list_all',
17-
'RunFailedError',
14+
'create','list_all',
1815
'SendChannel','RecvChannel',
19-
'create_channel','list_all_channels','is_shareable',
20-
'ChannelError','ChannelNotFoundError',
21-
'ChannelEmptyError',
22-
]
16+
'ChannelError','ChannelNotFoundError','ChannelEmptyError',
17+
]
2318

2419

25-
classRunFailedError(RuntimeError):
26-
27-
def__init__(self,excinfo):
28-
msg=excinfo.formatted
29-
ifnotmsg:
30-
ifexcinfo.typeandsnapshot.msg:
31-
msg=f'{snapshot.type.__name__}:{snapshot.msg}'
32-
else:
33-
msg=snapshot.type.__name__orsnapshot.msg
34-
super().__init__(msg)
35-
self.snapshot=excinfo
36-
37-
38-
defcreate(*,isolated=True):
39-
"""Return a new (idle) Python interpreter."""
40-
id=_interpreters.create(isolated=isolated)
41-
returnInterpreter(id,isolated=isolated)
42-
43-
44-
deflist_all():
45-
"""Return all existing interpreters."""
46-
return [Interpreter(id)foridin_interpreters.list_all()]
47-
48-
49-
defget_current():
50-
"""Return the currently running interpreter."""
51-
id=_interpreters.get_current()
52-
returnInterpreter(id)
53-
54-
55-
defget_main():
56-
"""Return the main interpreter."""
57-
id=_interpreters.get_main()
58-
returnInterpreter(id)
59-
60-
61-
classInterpreter:
62-
"""A single Python interpreter."""
63-
64-
def__init__(self,id,*,isolated=None):
65-
ifnotisinstance(id, (int,_interpreters.InterpreterID)):
66-
raiseTypeError(f'id must be an int, got{id!r}')
67-
self._id=id
68-
self._isolated=isolated
69-
70-
def__repr__(self):
71-
data=dict(id=int(self._id),isolated=self._isolated)
72-
kwargs= (f'{k}={v!r}'fork,vindata.items())
73-
returnf'{type(self).__name__}({", ".join(kwargs)})'
74-
75-
def__hash__(self):
76-
returnhash(self._id)
77-
78-
def__eq__(self,other):
79-
ifnotisinstance(other,Interpreter):
80-
returnNotImplemented
81-
else:
82-
returnother._id==self._id
83-
84-
@property
85-
defid(self):
86-
returnself._id
87-
88-
@property
89-
defisolated(self):
90-
ifself._isolatedisNone:
91-
# XXX The low-level function has not been added yet.
92-
# See bpo-....
93-
self._isolated=_interpreters.is_isolated(self._id)
94-
returnself._isolated
95-
96-
defis_running(self):
97-
"""Return whether or not the identified interpreter is running."""
98-
return_interpreters.is_running(self._id)
99-
100-
defclose(self):
101-
"""Finalize and destroy the interpreter.
102-
103-
Attempting to destroy the current interpreter results
104-
in a RuntimeError.
105-
"""
106-
return_interpreters.destroy(self._id)
107-
108-
# XXX Rename "run" to "exec"?
109-
defrun(self,src_str,/,channels=None):
110-
"""Run the given source code in the interpreter.
111-
112-
This is essentially the same as calling the builtin "exec"
113-
with this interpreter, using the __dict__ of its __main__
114-
module as both globals and locals.
115-
116-
There is no return value.
117-
118-
If the code raises an unhandled exception then a RunFailedError
119-
is raised, which summarizes the unhandled exception. The actual
120-
exception is discarded because objects cannot be shared between
121-
interpreters.
122-
123-
This blocks the current Python thread until done. During
124-
that time, the previous interpreter is allowed to run
125-
in other threads.
126-
"""
127-
excinfo=_interpreters.exec(self._id,src_str,channels)
128-
ifexcinfoisnotNone:
129-
raiseRunFailedError(excinfo)
130-
131-
132-
defcreate_channel():
20+
defcreate():
13321
"""Return (recv, send) for a new cross-interpreter channel.
13422
13523
The channel may be used to pass data safely between interpreters.
@@ -139,7 +27,7 @@ def create_channel():
13927
returnrecv,send
14028

14129

142-
deflist_all_channels():
30+
deflist_all():
14331
"""Return a list of (recv, send) for all open channels."""
14432
return [(RecvChannel(cid),SendChannel(cid))
14533
forcidin_channels.list_all()]

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp