From 21597b09173c00927d0b8fc6e8572274ca9e7cfc Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 27 May 2020 21:34:53 +0100 Subject: [PATCH] Revert "bpo-32604: PEP 554 for use in test suite (GH-19985)" This reverts commit 9d17cbf33df7cfb67ca0f37f6463ba5c18676641. --- Lib/test/support/interpreters.py | 183 ------ Lib/test/support/interpreters.rst | 145 ----- Lib/test/test_interpreters.py | 535 ------------------ .../2020-05-07-22-00-12.bpo-39881.E1xsNv.rst | 2 - 4 files changed, 865 deletions(-) delete mode 100644 Lib/test/support/interpreters.py delete mode 100644 Lib/test/support/interpreters.rst delete mode 100644 Lib/test/test_interpreters.py delete mode 100644 Misc/NEWS.d/next/Library/2020-05-07-22-00-12.bpo-39881.E1xsNv.rst diff --git a/Lib/test/support/interpreters.py b/Lib/test/support/interpreters.py deleted file mode 100644 index ef9dcafb2a3860..00000000000000 --- a/Lib/test/support/interpreters.py +++ /dev/null @@ -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 diff --git a/Lib/test/support/interpreters.rst b/Lib/test/support/interpreters.rst deleted file mode 100644 index 37a60b1072a669..00000000000000 --- a/Lib/test/support/interpreters.rst +++ /dev/null @@ -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. diff --git a/Lib/test/test_interpreters.py b/Lib/test/test_interpreters.py deleted file mode 100644 index 3451a4c8759d8b..00000000000000 --- a/Lib/test/test_interpreters.py +++ /dev/null @@ -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) diff --git a/Misc/NEWS.d/next/Library/2020-05-07-22-00-12.bpo-39881.E1xsNv.rst b/Misc/NEWS.d/next/Library/2020-05-07-22-00-12.bpo-39881.E1xsNv.rst deleted file mode 100644 index 1129cd7649b96a..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-07-22-00-12.bpo-39881.E1xsNv.rst +++ /dev/null @@ -1,2 +0,0 @@ -PEP 554 for use in the test suite. -(Patch By Joannah Nanjekye) \ No newline at end of file pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy