@@ -74,51 +74,77 @@ def __str__(self):
7474def create ():
7575 """Return a new (idle) Python interpreter."""
7676 id = _interpreters .create (reqrefs = True )
77- return Interpreter (id )
77+ return Interpreter (id , _ownsref = True )
7878
7979
8080def list_all ():
8181 """Return all existing interpreters."""
82- return [Interpreter (id )
83- for id , in _interpreters .list_all ()]
82+ return [Interpreter (id , _whence = whence )
83+ for id , whence in _interpreters .list_all (require_ready = True )]
8484
8585
8686def get_current ():
8787 """Return the currently running interpreter."""
88- id , = _interpreters .get_current ()
89- return Interpreter (id )
88+ id , whence = _interpreters .get_current ()
89+ return Interpreter (id , _whence = whence )
9090
9191
9292def get_main ():
9393 """Return the main interpreter."""
94- id , = _interpreters .get_main ()
95- return Interpreter (id )
94+ id , whence = _interpreters .get_main ()
95+ assert whence == _interpreters .WHENCE_RUNTIME , repr (whence )
96+ return Interpreter (id , _whence = whence )
9697
9798
9899_known = weakref .WeakValueDictionary ()
99100
100101class Interpreter :
101- """A single Python interpreter."""
102+ """A single Python interpreter.
102103
103- def __new__ (cls , id , / ):
104+ Attributes:
105+
106+ "id" - the unique process-global ID number for the interpreter
107+ "whence" - indicates where the interpreter was created
108+
109+ If the interpreter wasn't created by this module
110+ then any method that modifies the interpreter will fail,
111+ i.e. .close(), .prepare_main(), .exec(), and .call()
112+ """
113+
114+ _WHENCE_TO_STR = {
115+ _interpreters .WHENCE_UNKNOWN : 'unknown' ,
116+ _interpreters .WHENCE_RUNTIME : 'runtime init' ,
117+ _interpreters .WHENCE_LEGACY_CAPI : 'legacy C-API' ,
118+ _interpreters .WHENCE_CAPI : 'C-API' ,
119+ _interpreters .WHENCE_XI : 'cross-interpreter C-API' ,
120+ _interpreters .WHENCE_STDLIB : '_interpreters module' ,
121+ }
122+
123+ def __new__ (cls , id , / , _whence = None , _ownsref = None ):
104124 # There is only one instance for any given ID.
105125 if not isinstance (id , int ):
106126 raise TypeError (f'id must be an int, got { id !r} ' )
107127 id = int (id )
128+ if _whence is None :
129+ if _ownsref :
130+ _whence = _interpreters .WHENCE_STDLIB
131+ else :
132+ _whence = _interpreters .whence (id )
133+ assert _whence in cls ._WHENCE_TO_STR , repr (_whence )
134+ if _ownsref is None :
135+ _ownsref = (_whence == _interpreters .WHENCE_STDLIB )
108136 try :
109137 self = _known [id ]
110138 assert hasattr (self , '_ownsref' )
111139 except KeyError :
112- # This may raise InterpreterNotFoundError:
113- _interpreters .incref (id )
114- try :
115- self = super ().__new__ (cls )
116- self ._id = id
117- self ._ownsref = True
118- except BaseException :
119- _interpreters .decref (id )
120- raise
140+ self = super ().__new__ (cls )
121141 _known [id ] = self
142+ self ._id = id
143+ self ._whence = _whence
144+ self ._ownsref = _ownsref
145+ if _ownsref :
146+ # This may raise InterpreterNotFoundError:
147+ _interpreters .incref (id )
122148 return self
123149
124150 def __repr__ (self ):
@@ -143,33 +169,40 @@ def _decref(self):
143169 return
144170 self ._ownsref = False
145171 try :
146- _interpreters .decref (self .id )
172+ _interpreters .decref (self ._id )
147173 except InterpreterNotFoundError :
148174 pass
149175
150176 @property
151177 def id (self ):
152178 return self ._id
153179
180+ @property
181+ def whence (self ):
182+ return self ._WHENCE_TO_STR [self ._whence ]
183+
154184 def is_running (self ):
155185 """Return whether or not the identified interpreter is running."""
156186 return _interpreters .is_running (self ._id )
157187
188+ # Everything past here is available only to interpreters created by
189+ # interpreters.create().
190+
158191 def close (self ):
159192 """Finalize and destroy the interpreter.
160193
161194 Attempting to destroy the current interpreter results
162195 in an InterpreterError.
163196 """
164- return _interpreters .destroy (self ._id )
197+ return _interpreters .destroy (self ._id , restrict = True )
165198
166199 def prepare_main (self , ns = None , / , ** kwargs ):
167200 """Bind the given values into the interpreter's __main__.
168201
169202 The values must be shareable.
170203 """
171204 ns = dict (ns , ** kwargs ) if ns is not None else kwargs
172- _interpreters .set___main___attrs (self ._id , ns )
205+ _interpreters .set___main___attrs (self ._id , ns , restrict = True )
173206
174207 def exec (self , code , / ):
175208 """Run the given source code in the interpreter.
@@ -189,7 +222,7 @@ def exec(self, code, /):
189222 that time, the previous interpreter is allowed to run
190223 in other threads.
191224 """
192- excinfo = _interpreters .exec (self ._id , code )
225+ excinfo = _interpreters .exec (self ._id , code , restrict = True )
193226 if excinfo is not None :
194227 raise ExecutionFailed (excinfo )
195228
@@ -209,7 +242,7 @@ def call(self, callable, /):
209242 # XXX Support args and kwargs.
210243 # XXX Support arbitrary callables.
211244 # XXX Support returning the return value (e.g. via pickle).
212- excinfo = _interpreters .call (self ._id , callable )
245+ excinfo = _interpreters .call (self ._id , callable , restrict = True )
213246 if excinfo is not None :
214247 raise ExecutionFailed (excinfo )
215248
0 commit comments