Skip to content

Commit 239808c

Browse files
gh-158370: Implement the context manager protocol for Interpreter objects (GH-158372)
1 parent 99edd54 commit 239808c

5 files changed

Lines changed: 50 additions & 0 deletions

File tree

‎Doc/library/concurrent.interpreters.rst‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,16 @@ Interpreter objects
244244
Generally, :class:`Interpreter` shouldn't be called directly.
245245
Instead, use :func:`create` or one of the other module functions.
246246

247+
:class:`!Interpreter` objects support the :term:`context manager`
248+
protocol. Exiting the :keyword:`with` block calls :meth:`close`::
249+
250+
with interpreters.create() as interp:
251+
interp.exec('print("hello")')
252+
253+
.. versionchanged:: next
254+
Added support for using :class:`!Interpreter` objects in
255+
a :term:`context manager`.
256+
247257
.. attribute:: id
248258

249259
(read-only)

‎Doc/whatsnew/3.16.rst‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,13 @@ concurrent.futures
192192
Use the :meth:`!close` method to explicitly close the iterator.
193193
(Contributed by xzmeng and Serhiy Storchaka in :gh:`108518`.)
194194

195+
concurrent.interpreters
196+
-----------------------
197+
198+
* :class:`~concurrent.interpreters.Interpreter` objects now support the
199+
:term:`context manager` protocol. Exiting the :keyword:`with` block calls
200+
:meth:`~concurrent.interpreters.Interpreter.close`.
201+
(Contributed by Peter Bierma in :gh:`158370`.)
195202

196203
csv
197204
---

‎Lib/concurrent/interpreters/__init__.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,12 @@ def close(self):
192192
"""
193193
return _interpreters.destroy(self._id, restrict=True)
194194

195+
def __enter__(self):
196+
return self
197+
198+
def __exit__(self, *exc_info):
199+
self.close()
200+
195201
def prepare_main(self, ns=None, /, **kwargs):
196202
"""Bind the given values into the interpreter's __main__.
197203

‎Lib/test/test_interpreters/test_api.py‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,31 @@ def task():
832832
assert_python_ok('-c', code)
833833

834834

835+
class TestInterpreterContextManager(TestBase):
836+
837+
def test_basic(self):
838+
main, = interpreters.list_all()
839+
with interpreters.create() as interp:
840+
self.assertIsInstance(interp, interpreters.Interpreter)
841+
self.assertEqual(interpreters.list_all(), [main, interp])
842+
self.assertEqual(interpreters.list_all(), [main])
843+
with self.assertRaises(InterpreterNotFoundError):
844+
interp.exec('pass')
845+
846+
def test_exception(self):
847+
main, = interpreters.list_all()
848+
with self.assertRaises(ZeroDivisionError):
849+
with interpreters.create() as interp:
850+
1/0
851+
self.assertEqual(interpreters.list_all(), [main])
852+
853+
def test_main(self):
854+
main, = interpreters.list_all()
855+
with self.assertRaises(InterpreterError):
856+
with main:
857+
pass
858+
859+
835860
class TestInterpreterPrepareMain(TestBase):
836861

837862
def test_empty(self):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:class:`concurrent.interpreters.Interpreter` objects now support the
2+
:term:`context manager` protocol.

0 commit comments

Comments
 (0)