mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	Revert "bpo-32604: PEP 554 for use in test suite (GH-19985)" (#20465)
This reverts commit 9d17cbf33d.
			
			
This commit is contained in:
		
							parent
							
								
									76ef255bde
								
							
						
					
					
						commit
						7d80b35af1
					
				
					 4 changed files with 0 additions and 865 deletions
				
			
		|  | @ -1,183 +0,0 @@ | |||
| """Subinterpreters High Level Module.""" | ||||
| 
 | ||||
| import _xxsubinterpreters as _interpreters | ||||
| 
 | ||||
| # aliases: | ||||
| from _xxsubinterpreters import ( | ||||
|     ChannelError, ChannelNotFoundError, ChannelEmptyError, | ||||
|     is_shareable, | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| __all__ = [ | ||||
|     'Interpreter', 'get_current', 'get_main', 'create', 'list_all', | ||||
|     'SendChannel', 'RecvChannel', | ||||
|     'create_channel', 'list_all_channels', 'is_shareable', | ||||
|     'ChannelError', 'ChannelNotFoundError', | ||||
|     'ChannelEmptyError', | ||||
|     ] | ||||
| 
 | ||||
| 
 | ||||
| def create(*, isolated=True): | ||||
|     """ | ||||
|     Initialize a new (idle) Python interpreter. | ||||
|     """ | ||||
|     id = _interpreters.create(isolated=isolated) | ||||
|     return Interpreter(id, isolated=isolated) | ||||
| 
 | ||||
| 
 | ||||
| def list_all(): | ||||
|     """ | ||||
|     Get all existing interpreters. | ||||
|     """ | ||||
|     return [Interpreter(id) for id in | ||||
|             _interpreters.list_all()] | ||||
| 
 | ||||
| 
 | ||||
| def get_current(): | ||||
|     """ | ||||
|     Get the currently running interpreter. | ||||
|     """ | ||||
|     id = _interpreters.get_current() | ||||
|     return Interpreter(id) | ||||
| 
 | ||||
| 
 | ||||
| def get_main(): | ||||
|     """ | ||||
|     Get the main interpreter. | ||||
|     """ | ||||
|     id = _interpreters.get_main() | ||||
|     return Interpreter(id) | ||||
| 
 | ||||
| 
 | ||||
| class Interpreter: | ||||
|     """ | ||||
|     The Interpreter object represents | ||||
|     a single interpreter. | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, id, *, isolated=None): | ||||
|         self._id = id | ||||
|         self._isolated = isolated | ||||
| 
 | ||||
|     @property | ||||
|     def id(self): | ||||
|         return self._id | ||||
| 
 | ||||
|     @property | ||||
|     def isolated(self): | ||||
|         if self._isolated is None: | ||||
|             self._isolated = _interpreters.is_isolated(self._id) | ||||
|         return self._isolated | ||||
| 
 | ||||
|     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 run(self, src_str, /, *, channels=None): | ||||
|         """ | ||||
|         Run the given source code in the interpreter. | ||||
|         This blocks the current Python thread until done. | ||||
|         """ | ||||
|         _interpreters.run_string(self._id, src_str) | ||||
| 
 | ||||
| 
 | ||||
| def create_channel(): | ||||
|     """ | ||||
|     Create a new channel for passing data between | ||||
|     interpreters. | ||||
|     """ | ||||
| 
 | ||||
|     cid = _interpreters.channel_create() | ||||
|     return (RecvChannel(cid), SendChannel(cid)) | ||||
| 
 | ||||
| 
 | ||||
| def list_all_channels(): | ||||
|     """ | ||||
|     Get all open channels. | ||||
|     """ | ||||
|     return [(RecvChannel(cid), SendChannel(cid)) | ||||
|             for cid in _interpreters.channel_list_all()] | ||||
| 
 | ||||
| 
 | ||||
| _NOT_SET = object() | ||||
| 
 | ||||
| 
 | ||||
| class RecvChannel: | ||||
|     """ | ||||
|     The RecvChannel object represents | ||||
|     a recieving channel. | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, id): | ||||
|         self._id = id | ||||
| 
 | ||||
|     def recv(self, *, _delay=10 / 1000):  # 10 milliseconds | ||||
|         """ | ||||
|         Get the next object from the channel, | ||||
|         and wait if none have been sent. | ||||
|         Associate the interpreter with the channel. | ||||
|         """ | ||||
|         import time | ||||
|         sentinel = object() | ||||
|         obj = _interpreters.channel_recv(self._id, sentinel) | ||||
|         while obj is sentinel: | ||||
|             time.sleep(_delay) | ||||
|             obj = _interpreters.channel_recv(self._id, sentinel) | ||||
|         return obj | ||||
| 
 | ||||
|     def recv_nowait(self, default=_NOT_SET): | ||||
|         """ | ||||
|         Like recv(), but return the default | ||||
|         instead of waiting. | ||||
| 
 | ||||
|         This function is blocked by a missing low-level | ||||
|         implementation of channel_recv_wait(). | ||||
|         """ | ||||
|         if default is _NOT_SET: | ||||
|             return _interpreters.channel_recv(self._id) | ||||
|         else: | ||||
|             return _interpreters.channel_recv(self._id, default) | ||||
| 
 | ||||
| 
 | ||||
| class SendChannel: | ||||
|     """ | ||||
|     The SendChannel object represents | ||||
|     a sending channel. | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, id): | ||||
|         self._id = id | ||||
| 
 | ||||
|     def send(self, obj): | ||||
|         """ | ||||
|         Send the object (i.e. its data) to the receiving | ||||
|         end of the channel and wait. Associate the interpreter | ||||
|         with the channel. | ||||
|         """ | ||||
|         import time | ||||
|         _interpreters.channel_send(self._id, obj) | ||||
|         time.sleep(2) | ||||
| 
 | ||||
|     def send_nowait(self, obj): | ||||
|         """ | ||||
|         Like send(), but return False if not received. | ||||
| 
 | ||||
|         This function is blocked by a missing low-level | ||||
|         implementation of channel_send_wait(). | ||||
|         """ | ||||
| 
 | ||||
|         _interpreters.channel_send(self._id, obj) | ||||
|         return False | ||||
|  | @ -1,145 +0,0 @@ | |||
| High-level implementation of Subinterpreters | ||||
| ============================================ | ||||
| 
 | ||||
| **Source code:** :source:`Lib/test/support/_interpreters.py` | ||||
| 
 | ||||
| -------------- | ||||
| 
 | ||||
| This module provides high-level tools for working with sub-interpreters, | ||||
| such as creating them, running code in them, or sending data between them. | ||||
| It is a wrapper around the low-level ``__xxsubinterpreters`` module. | ||||
| 
 | ||||
| .. versionchanged:: added in 3.9 | ||||
| 
 | ||||
| Interpreter Objects | ||||
| ------------------- | ||||
| 
 | ||||
| The ``Interpreter`` object represents a single interpreter. | ||||
| 
 | ||||
| .. class:: Interpreter(id) | ||||
| 
 | ||||
|     The class implementing a subinterpreter object. | ||||
| 
 | ||||
|     .. method:: is_running() | ||||
| 
 | ||||
|        Return ``True`` if the identified interpreter is running. | ||||
| 
 | ||||
|     .. method:: close() | ||||
| 
 | ||||
|        Destroy the interpreter. Attempting to destroy the current | ||||
|        interpreter results in a `RuntimeError`. | ||||
| 
 | ||||
|     .. method:: run(self, src_str, /, *, channels=None): | ||||
| 
 | ||||
|        Run the given source code in the interpreter. This blocks | ||||
|        the current thread until done. ``channels`` should be in | ||||
|        the form : `(RecvChannel, SendChannel)`. | ||||
| 
 | ||||
| RecvChannel Objects | ||||
| ------------------- | ||||
| 
 | ||||
| The ``RecvChannel`` object represents a recieving channel. | ||||
| 
 | ||||
| .. class:: RecvChannel(id) | ||||
| 
 | ||||
|     This class represents the receiving end of a channel. | ||||
| 
 | ||||
|     .. method:: recv() | ||||
| 
 | ||||
|         Get the next object from the channel, and wait if | ||||
|         none have been sent. Associate the interpreter | ||||
|         with the channel. | ||||
| 
 | ||||
|     .. method:: recv_nowait(default=None) | ||||
| 
 | ||||
|         Like ``recv()``, but return the default result | ||||
|         instead of waiting. | ||||
| 
 | ||||
| 
 | ||||
| SendChannel Objects | ||||
| -------------------- | ||||
| 
 | ||||
| The ``SendChannel`` object represents a sending channel. | ||||
| 
 | ||||
| .. class:: SendChannel(id) | ||||
| 
 | ||||
|     This class represents the sending end of a channel. | ||||
| 
 | ||||
|     .. method:: send(obj) | ||||
| 
 | ||||
|        Send the object ``obj`` to the receiving end of the channel | ||||
|        and wait. Associate the interpreter with the channel. | ||||
| 
 | ||||
|     .. method:: send_nowait(obj) | ||||
| 
 | ||||
|         Similar to ``send()``, but returns ``False`` if | ||||
|         *obj* is not immediately received instead of blocking. | ||||
| 
 | ||||
| 
 | ||||
| This module defines the following global functions: | ||||
| 
 | ||||
| 
 | ||||
| .. function:: is_shareable(obj) | ||||
| 
 | ||||
|    Return ``True`` if the object's data can be shared between | ||||
|    interpreters. | ||||
| 
 | ||||
| .. function:: create_channel() | ||||
| 
 | ||||
|    Create a new channel for passing data between interpreters. | ||||
| 
 | ||||
| .. function:: list_all_channels() | ||||
| 
 | ||||
|    Return all open channels. | ||||
| 
 | ||||
| .. function:: create(*, isolated=True) | ||||
| 
 | ||||
|    Initialize a new (idle) Python interpreter. Get the currently | ||||
|    running interpreter. This method returns an ``Interpreter`` object. | ||||
| 
 | ||||
| .. function:: get_current() | ||||
| 
 | ||||
|    Get the currently running interpreter. This method returns | ||||
|    an ``Interpreter`` object. | ||||
| 
 | ||||
| .. function:: get_main() | ||||
| 
 | ||||
|    Get the main interpreter. This method returns | ||||
|    an ``Interpreter`` object. | ||||
| 
 | ||||
| .. function:: list_all() | ||||
| 
 | ||||
|    Get all existing interpreters. Returns a list | ||||
|    of ``Interpreter`` objects. | ||||
| 
 | ||||
| This module also defines the following exceptions. | ||||
| 
 | ||||
| .. exception:: RunFailedError | ||||
| 
 | ||||
|    This exception, a subclass of :exc:`RuntimeError`, is raised when the | ||||
|    ``Interpreter.run()`` results in an uncaught exception. | ||||
| 
 | ||||
| .. exception:: ChannelError | ||||
| 
 | ||||
|    This exception is a subclass of :exc:`Exception`, and is the base | ||||
|    class for all channel-related exceptions. | ||||
| 
 | ||||
| .. exception:: ChannelNotFoundError | ||||
| 
 | ||||
|    This exception is a subclass of :exc:`ChannelError`, and is raised | ||||
|    when the identified channel is not found. | ||||
| 
 | ||||
| .. exception:: ChannelEmptyError | ||||
| 
 | ||||
|    This exception is a subclass of :exc:`ChannelError`, and is raised when | ||||
|    the channel is unexpectedly empty. | ||||
| 
 | ||||
| .. exception:: ChannelNotEmptyError | ||||
| 
 | ||||
|    This exception is a subclass of :exc:`ChannelError`, and is raised when | ||||
|    the channel is unexpectedly not empty. | ||||
| 
 | ||||
| .. exception:: NotReceivedError | ||||
| 
 | ||||
|    This exception is a subclass of :exc:`ChannelError`, and is raised when | ||||
|    nothing was waiting to receive a sent object. | ||||
|  | @ -1,535 +0,0 @@ | |||
| import contextlib | ||||
| import os | ||||
| import threading | ||||
| from textwrap import dedent | ||||
| import unittest | ||||
| import time | ||||
| 
 | ||||
| import _xxsubinterpreters as _interpreters | ||||
| from test.support import interpreters | ||||
| 
 | ||||
| 
 | ||||
| def _captured_script(script): | ||||
|     r, w = os.pipe() | ||||
|     indented = script.replace('\n', '\n                ') | ||||
|     wrapped = dedent(f""" | ||||
|         import contextlib | ||||
|         with open({w}, 'w') as spipe: | ||||
|             with contextlib.redirect_stdout(spipe): | ||||
|                 {indented} | ||||
|         """) | ||||
|     return wrapped, open(r) | ||||
| 
 | ||||
| 
 | ||||
| def clean_up_interpreters(): | ||||
|     for interp in interpreters.list_all(): | ||||
|         if interp.id == 0:  # main | ||||
|             continue | ||||
|         try: | ||||
|             interp.close() | ||||
|         except RuntimeError: | ||||
|             pass  # already destroyed | ||||
| 
 | ||||
| 
 | ||||
| def _run_output(interp, request, shared=None): | ||||
|     script, rpipe = _captured_script(request) | ||||
|     with rpipe: | ||||
|         interp.run(script) | ||||
|         return rpipe.read() | ||||
| 
 | ||||
| 
 | ||||
| @contextlib.contextmanager | ||||
| def _running(interp): | ||||
|     r, w = os.pipe() | ||||
|     def run(): | ||||
|         interp.run(dedent(f""" | ||||
|             # wait for "signal" | ||||
|             with open({r}) as rpipe: | ||||
|                 rpipe.read() | ||||
|             """)) | ||||
| 
 | ||||
|     t = threading.Thread(target=run) | ||||
|     t.start() | ||||
| 
 | ||||
|     yield | ||||
| 
 | ||||
|     with open(w, 'w') as spipe: | ||||
|         spipe.write('done') | ||||
|     t.join() | ||||
| 
 | ||||
| 
 | ||||
| class TestBase(unittest.TestCase): | ||||
| 
 | ||||
|     def tearDown(self): | ||||
|         clean_up_interpreters() | ||||
| 
 | ||||
| 
 | ||||
| class CreateTests(TestBase): | ||||
| 
 | ||||
|     def test_in_main(self): | ||||
|         interp = interpreters.create() | ||||
|         lst = interpreters.list_all() | ||||
|         self.assertEqual(interp.id, lst[1].id) | ||||
| 
 | ||||
|     def test_in_thread(self): | ||||
|         lock = threading.Lock() | ||||
|         id = None | ||||
|         interp = interpreters.create() | ||||
|         lst = interpreters.list_all() | ||||
|         def f(): | ||||
|             nonlocal id | ||||
|             id = interp.id | ||||
|             lock.acquire() | ||||
|             lock.release() | ||||
| 
 | ||||
|         t = threading.Thread(target=f) | ||||
|         with lock: | ||||
|             t.start() | ||||
|         t.join() | ||||
|         self.assertEqual(interp.id, lst[1].id) | ||||
| 
 | ||||
|     def test_in_subinterpreter(self): | ||||
|         main, = interpreters.list_all() | ||||
|         interp = interpreters.create() | ||||
|         out = _run_output(interp, dedent(""" | ||||
|             from test.support import interpreters | ||||
|             interp = interpreters.create() | ||||
|             print(interp) | ||||
|             """)) | ||||
|         interp2 = out.strip() | ||||
| 
 | ||||
|         self.assertEqual(len(set(interpreters.list_all())), len({main, interp, interp2})) | ||||
| 
 | ||||
|     def test_after_destroy_all(self): | ||||
|         before = set(interpreters.list_all()) | ||||
|         # Create 3 subinterpreters. | ||||
|         interp_lst = [] | ||||
|         for _ in range(3): | ||||
|             interps = interpreters.create() | ||||
|             interp_lst.append(interps) | ||||
|         # Now destroy them. | ||||
|         for interp in interp_lst: | ||||
|             interp.close() | ||||
|         # Finally, create another. | ||||
|         interp = interpreters.create() | ||||
|         self.assertEqual(len(set(interpreters.list_all())), len(before | {interp})) | ||||
| 
 | ||||
|     def test_after_destroy_some(self): | ||||
|         before = set(interpreters.list_all()) | ||||
|         # Create 3 subinterpreters. | ||||
|         interp1 = interpreters.create() | ||||
|         interp2 = interpreters.create() | ||||
|         interp3 = interpreters.create() | ||||
|         # Now destroy 2 of them. | ||||
|         interp1.close() | ||||
|         interp2.close() | ||||
|         # Finally, create another. | ||||
|         interp = interpreters.create() | ||||
|         self.assertEqual(len(set(interpreters.list_all())), len(before | {interp3, interp})) | ||||
| 
 | ||||
| 
 | ||||
| class GetCurrentTests(TestBase): | ||||
| 
 | ||||
|     def test_main(self): | ||||
|         main_interp_id = _interpreters.get_main() | ||||
|         cur_interp_id =  interpreters.get_current().id | ||||
|         self.assertEqual(cur_interp_id, main_interp_id) | ||||
| 
 | ||||
|     def test_subinterpreter(self): | ||||
|         main = _interpreters.get_main() | ||||
|         interp = interpreters.create() | ||||
|         out = _run_output(interp, dedent(""" | ||||
|             from test.support import interpreters | ||||
|             cur = interpreters.get_current() | ||||
|             print(cur) | ||||
|             """)) | ||||
|         cur = out.strip() | ||||
|         self.assertNotEqual(cur, main) | ||||
| 
 | ||||
| 
 | ||||
| class ListAllTests(TestBase): | ||||
| 
 | ||||
|     def test_initial(self): | ||||
|         interps = interpreters.list_all() | ||||
|         self.assertEqual(1, len(interps)) | ||||
| 
 | ||||
|     def test_after_creating(self): | ||||
|         main = interpreters.get_current() | ||||
|         first = interpreters.create() | ||||
|         second = interpreters.create() | ||||
| 
 | ||||
|         ids = [] | ||||
|         for interp in interpreters.list_all(): | ||||
|             ids.append(interp.id) | ||||
| 
 | ||||
|         self.assertEqual(ids, [main.id, first.id, second.id]) | ||||
| 
 | ||||
|     def test_after_destroying(self): | ||||
|         main = interpreters.get_current() | ||||
|         first = interpreters.create() | ||||
|         second = interpreters.create() | ||||
|         first.close() | ||||
| 
 | ||||
|         ids = [] | ||||
|         for interp in interpreters.list_all(): | ||||
|             ids.append(interp.id) | ||||
| 
 | ||||
|         self.assertEqual(ids, [main.id, second.id]) | ||||
| 
 | ||||
| 
 | ||||
| class TestInterpreterId(TestBase): | ||||
| 
 | ||||
|     def test_in_main(self): | ||||
|         main = interpreters.get_current() | ||||
|         self.assertEqual(0, main.id) | ||||
| 
 | ||||
|     def test_with_custom_num(self): | ||||
|         interp = interpreters.Interpreter(1) | ||||
|         self.assertEqual(1, interp.id) | ||||
| 
 | ||||
|     def test_for_readonly_property(self): | ||||
|         interp = interpreters.Interpreter(1) | ||||
|         with self.assertRaises(AttributeError): | ||||
|             interp.id = 2 | ||||
| 
 | ||||
| 
 | ||||
| class TestInterpreterIsRunning(TestBase): | ||||
| 
 | ||||
|     def test_main(self): | ||||
|         main = interpreters.get_current() | ||||
|         self.assertTrue(main.is_running()) | ||||
| 
 | ||||
|     def test_subinterpreter(self): | ||||
|         interp = interpreters.create() | ||||
|         self.assertFalse(interp.is_running()) | ||||
| 
 | ||||
|         with _running(interp): | ||||
|             self.assertTrue(interp.is_running()) | ||||
|         self.assertFalse(interp.is_running()) | ||||
| 
 | ||||
|     def test_from_subinterpreter(self): | ||||
|         interp = interpreters.create() | ||||
|         out = _run_output(interp, dedent(f""" | ||||
|             import _xxsubinterpreters as _interpreters | ||||
|             if _interpreters.is_running({interp.id}): | ||||
|                 print(True) | ||||
|             else: | ||||
|                 print(False) | ||||
|             """)) | ||||
|         self.assertEqual(out.strip(), 'True') | ||||
| 
 | ||||
|     def test_already_destroyed(self): | ||||
|         interp = interpreters.create() | ||||
|         interp.close() | ||||
|         with self.assertRaises(RuntimeError): | ||||
|             interp.is_running() | ||||
| 
 | ||||
| 
 | ||||
| class TestInterpreterDestroy(TestBase): | ||||
| 
 | ||||
|     def test_basic(self): | ||||
|         interp1 = interpreters.create() | ||||
|         interp2 = interpreters.create() | ||||
|         interp3 = interpreters.create() | ||||
|         self.assertEqual(4, len(interpreters.list_all())) | ||||
|         interp2.close() | ||||
|         self.assertEqual(3, len(interpreters.list_all())) | ||||
| 
 | ||||
|     def test_all(self): | ||||
|         before = set(interpreters.list_all()) | ||||
|         interps = set() | ||||
|         for _ in range(3): | ||||
|             interp = interpreters.create() | ||||
|             interps.add(interp) | ||||
|         self.assertEqual(len(set(interpreters.list_all())), len(before | interps)) | ||||
|         for interp in interps: | ||||
|             interp.close() | ||||
|         self.assertEqual(len(set(interpreters.list_all())), len(before)) | ||||
| 
 | ||||
|     def test_main(self): | ||||
|         main, = interpreters.list_all() | ||||
|         with self.assertRaises(RuntimeError): | ||||
|             main.close() | ||||
| 
 | ||||
|         def f(): | ||||
|             with self.assertRaises(RuntimeError): | ||||
|                 main.close() | ||||
| 
 | ||||
|         t = threading.Thread(target=f) | ||||
|         t.start() | ||||
|         t.join() | ||||
| 
 | ||||
|     def test_already_destroyed(self): | ||||
|         interp = interpreters.create() | ||||
|         interp.close() | ||||
|         with self.assertRaises(RuntimeError): | ||||
|             interp.close() | ||||
| 
 | ||||
|     def test_from_current(self): | ||||
|         main, = interpreters.list_all() | ||||
|         interp = interpreters.create() | ||||
|         script = dedent(f""" | ||||
|             from test.support import interpreters | ||||
|             try: | ||||
|                 main = interpreters.get_current() | ||||
|                 main.close() | ||||
|             except RuntimeError: | ||||
|                 pass | ||||
|             """) | ||||
| 
 | ||||
|         interp.run(script) | ||||
|         self.assertEqual(len(set(interpreters.list_all())), len({main, interp})) | ||||
| 
 | ||||
|     def test_from_sibling(self): | ||||
|         main, = interpreters.list_all() | ||||
|         interp1 = interpreters.create() | ||||
|         script = dedent(f""" | ||||
|             from test.support import interpreters | ||||
|             interp2 = interpreters.create() | ||||
|             interp2.close() | ||||
|             """) | ||||
|         interp1.run(script) | ||||
| 
 | ||||
|         self.assertEqual(len(set(interpreters.list_all())), len({main, interp1})) | ||||
| 
 | ||||
|     def test_from_other_thread(self): | ||||
|         interp = interpreters.create() | ||||
|         def f(): | ||||
|             interp.close() | ||||
| 
 | ||||
|         t = threading.Thread(target=f) | ||||
|         t.start() | ||||
|         t.join() | ||||
| 
 | ||||
|     def test_still_running(self): | ||||
|         main, = interpreters.list_all() | ||||
|         interp = interpreters.create() | ||||
|         with _running(interp): | ||||
|             with self.assertRaises(RuntimeError): | ||||
|                 interp.close() | ||||
|             self.assertTrue(interp.is_running()) | ||||
| 
 | ||||
| 
 | ||||
| class TestInterpreterRun(TestBase): | ||||
| 
 | ||||
|     SCRIPT = dedent(""" | ||||
|         with open('{}', 'w') as out: | ||||
|             out.write('{}') | ||||
|         """) | ||||
|     FILENAME = 'spam' | ||||
| 
 | ||||
|     def setUp(self): | ||||
|         super().setUp() | ||||
|         self.interp = interpreters.create() | ||||
|         self._fs = None | ||||
| 
 | ||||
|     def tearDown(self): | ||||
|         if self._fs is not None: | ||||
|             self._fs.close() | ||||
|         super().tearDown() | ||||
| 
 | ||||
|     @property | ||||
|     def fs(self): | ||||
|         if self._fs is None: | ||||
|             self._fs = FSFixture(self) | ||||
|         return self._fs | ||||
| 
 | ||||
|     def test_success(self): | ||||
|         script, file = _captured_script('print("it worked!", end="")') | ||||
|         with file: | ||||
|             self.interp.run(script) | ||||
|             out = file.read() | ||||
| 
 | ||||
|         self.assertEqual(out, 'it worked!') | ||||
| 
 | ||||
|     def test_in_thread(self): | ||||
|         script, file = _captured_script('print("it worked!", end="")') | ||||
|         with file: | ||||
|             def f(): | ||||
|                 self.interp.run(script) | ||||
| 
 | ||||
|             t = threading.Thread(target=f) | ||||
|             t.start() | ||||
|             t.join() | ||||
|             out = file.read() | ||||
| 
 | ||||
|         self.assertEqual(out, 'it worked!') | ||||
| 
 | ||||
|     @unittest.skipUnless(hasattr(os, 'fork'), "test needs os.fork()") | ||||
|     def test_fork(self): | ||||
|         import tempfile | ||||
|         with tempfile.NamedTemporaryFile('w+') as file: | ||||
|             file.write('') | ||||
|             file.flush() | ||||
| 
 | ||||
|             expected = 'spam spam spam spam spam' | ||||
|             script = dedent(f""" | ||||
|                 import os | ||||
|                 try: | ||||
|                     os.fork() | ||||
|                 except RuntimeError: | ||||
|                     with open('{file.name}', 'w') as out: | ||||
|                         out.write('{expected}') | ||||
|                 """) | ||||
|             self.interp.run(script) | ||||
| 
 | ||||
|             file.seek(0) | ||||
|             content = file.read() | ||||
|             self.assertEqual(content, expected) | ||||
| 
 | ||||
|     def test_already_running(self): | ||||
|         with _running(self.interp): | ||||
|             with self.assertRaises(RuntimeError): | ||||
|                 self.interp.run('print("spam")') | ||||
| 
 | ||||
|     def test_bad_script(self): | ||||
|         with self.assertRaises(TypeError): | ||||
|             self.interp.run(10) | ||||
| 
 | ||||
|     def test_bytes_for_script(self): | ||||
|         with self.assertRaises(TypeError): | ||||
|             self.interp.run(b'print("spam")') | ||||
| 
 | ||||
| 
 | ||||
| class TestIsShareable(TestBase): | ||||
| 
 | ||||
|     def test_default_shareables(self): | ||||
|         shareables = [ | ||||
|                 # singletons | ||||
|                 None, | ||||
|                 # builtin objects | ||||
|                 b'spam', | ||||
|                 'spam', | ||||
|                 10, | ||||
|                 -10, | ||||
|                 ] | ||||
|         for obj in shareables: | ||||
|             with self.subTest(obj): | ||||
|                 self.assertTrue( | ||||
|                     interpreters.is_shareable(obj)) | ||||
| 
 | ||||
|     def test_not_shareable(self): | ||||
|         class Cheese: | ||||
|             def __init__(self, name): | ||||
|                 self.name = name | ||||
|             def __str__(self): | ||||
|                 return self.name | ||||
| 
 | ||||
|         class SubBytes(bytes): | ||||
|             """A subclass of a shareable type.""" | ||||
| 
 | ||||
|         not_shareables = [ | ||||
|                 # singletons | ||||
|                 True, | ||||
|                 False, | ||||
|                 NotImplemented, | ||||
|                 ..., | ||||
|                 # builtin types and objects | ||||
|                 type, | ||||
|                 object, | ||||
|                 object(), | ||||
|                 Exception(), | ||||
|                 100.0, | ||||
|                 # user-defined types and objects | ||||
|                 Cheese, | ||||
|                 Cheese('Wensleydale'), | ||||
|                 SubBytes(b'spam'), | ||||
|                 ] | ||||
|         for obj in not_shareables: | ||||
|             with self.subTest(repr(obj)): | ||||
|                 self.assertFalse( | ||||
|                     interpreters.is_shareable(obj)) | ||||
| 
 | ||||
| 
 | ||||
| class TestChannel(TestBase): | ||||
| 
 | ||||
|     def test_create_cid(self): | ||||
|         r, s = interpreters.create_channel() | ||||
|         self.assertIsInstance(r, interpreters.RecvChannel) | ||||
|         self.assertIsInstance(s, interpreters.SendChannel) | ||||
| 
 | ||||
|     def test_sequential_ids(self): | ||||
|         before = interpreters.list_all_channels() | ||||
|         channels1 = interpreters.create_channel() | ||||
|         channels2 = interpreters.create_channel() | ||||
|         channels3 = interpreters.create_channel() | ||||
|         after = interpreters.list_all_channels() | ||||
| 
 | ||||
|         self.assertEqual(len(set(after) - set(before)), | ||||
|                          len({channels1, channels2, channels3})) | ||||
| 
 | ||||
| 
 | ||||
| class TestSendRecv(TestBase): | ||||
| 
 | ||||
|     def test_send_recv_main(self): | ||||
|         r, s = interpreters.create_channel() | ||||
|         orig = b'spam' | ||||
|         s.send(orig) | ||||
|         obj = r.recv() | ||||
| 
 | ||||
|         self.assertEqual(obj, orig) | ||||
|         self.assertIsNot(obj, orig) | ||||
| 
 | ||||
|     def test_send_recv_same_interpreter(self): | ||||
|         interp = interpreters.create() | ||||
|         out = _run_output(interp, dedent(""" | ||||
|             from test.support import interpreters | ||||
|             r, s = interpreters.create_channel() | ||||
|             orig = b'spam' | ||||
|             s.send(orig) | ||||
|             obj = r.recv() | ||||
|             assert obj is not orig | ||||
|             assert obj == orig | ||||
|             """)) | ||||
| 
 | ||||
|     def test_send_recv_different_threads(self): | ||||
|         r, s = interpreters.create_channel() | ||||
| 
 | ||||
|         def f(): | ||||
|             while True: | ||||
|                 try: | ||||
|                     obj = r.recv() | ||||
|                     break | ||||
|                 except interpreters.ChannelEmptyError: | ||||
|                     time.sleep(0.1) | ||||
|             s.send(obj) | ||||
|         t = threading.Thread(target=f) | ||||
|         t.start() | ||||
| 
 | ||||
|         s.send(b'spam') | ||||
|         t.join() | ||||
|         obj = r.recv() | ||||
| 
 | ||||
|         self.assertEqual(obj, b'spam') | ||||
| 
 | ||||
|     def test_send_recv_nowait_main(self): | ||||
|         r, s = interpreters.create_channel() | ||||
|         orig = b'spam' | ||||
|         s.send(orig) | ||||
|         obj = r.recv_nowait() | ||||
| 
 | ||||
|         self.assertEqual(obj, orig) | ||||
|         self.assertIsNot(obj, orig) | ||||
| 
 | ||||
|     def test_send_recv_nowait_same_interpreter(self): | ||||
|         interp = interpreters.create() | ||||
|         out = _run_output(interp, dedent(""" | ||||
|             from test.support import interpreters | ||||
|             r, s = interpreters.create_channel() | ||||
|             orig = b'spam' | ||||
|             s.send(orig) | ||||
|             obj = r.recv_nowait() | ||||
|             assert obj is not orig | ||||
|             assert obj == orig | ||||
|             """)) | ||||
| 
 | ||||
|         r, s = interpreters.create_channel() | ||||
| 
 | ||||
|         def f(): | ||||
|             while True: | ||||
|                 try: | ||||
|                     obj = r.recv_nowait() | ||||
|                     break | ||||
|                 except _interpreters.ChannelEmptyError: | ||||
|                     time.sleep(0.1) | ||||
|             s.send(obj) | ||||
|  | @ -1,2 +0,0 @@ | |||
| PEP 554 for use in the test suite. | ||||
| (Patch By Joannah Nanjekye) | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Pablo Galindo
						Pablo Galindo