diff options
Diffstat (limited to 'venv/lib/python3.11/site-packages/greenlet/tests')
50 files changed, 0 insertions, 4597 deletions
| diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__init__.py b/venv/lib/python3.11/site-packages/greenlet/tests/__init__.py deleted file mode 100644 index e249e35..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__init__.py +++ /dev/null @@ -1,237 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tests for greenlet. - -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import sys -import unittest - -from gc import collect -from gc import get_objects -from threading import active_count as active_thread_count -from time import sleep -from time import time - -import psutil - -from greenlet import greenlet as RawGreenlet -from greenlet import getcurrent - -from greenlet._greenlet import get_pending_cleanup_count -from greenlet._greenlet import get_total_main_greenlets - -from . import leakcheck - -PY312 = sys.version_info[:2] >= (3, 12) -WIN = sys.platform.startswith("win") - -class TestCaseMetaClass(type): -    # wrap each test method with -    # a) leak checks -    def __new__(cls, classname, bases, classDict): -        # pylint and pep8 fight over what this should be called (mcs or cls). -        # pylint gets it right, but we can't scope disable pep8, so we go with -        # its convention. -        # pylint: disable=bad-mcs-classmethod-argument -        check_totalrefcount = True - -        # Python 3: must copy, we mutate the classDict. Interestingly enough, -        # it doesn't actually error out, but under 3.6 we wind up wrapping -        # and re-wrapping the same items over and over and over. -        for key, value in list(classDict.items()): -            if key.startswith('test') and callable(value): -                classDict.pop(key) -                if check_totalrefcount: -                    value = leakcheck.wrap_refcount(value) -                classDict[key] = value -        return type.__new__(cls, classname, bases, classDict) - - -class TestCase(TestCaseMetaClass( -        "NewBase", -        (unittest.TestCase,), -        {})): - -    cleanup_attempt_sleep_duration = 0.001 -    cleanup_max_sleep_seconds = 1 - -    def wait_for_pending_cleanups(self, -                                  initial_active_threads=None, -                                  initial_main_greenlets=None): -        initial_active_threads = initial_active_threads or self.threads_before_test -        initial_main_greenlets = initial_main_greenlets or self.main_greenlets_before_test -        sleep_time = self.cleanup_attempt_sleep_duration -        # NOTE: This is racy! A Python-level thread object may be dead -        # and gone, but the C thread may not yet have fired its -        # destructors and added to the queue. There's no particular -        # way to know that's about to happen. We try to watch the -        # Python threads to make sure they, at least, have gone away. -        # Counting the main greenlets, which we can easily do deterministically, -        # also helps. - -        # Always sleep at least once to let other threads run -        sleep(sleep_time) -        quit_after = time() + self.cleanup_max_sleep_seconds -        # TODO: We could add an API that calls us back when a particular main greenlet is deleted? -        # It would have to drop the GIL -        while ( -                get_pending_cleanup_count() -                or active_thread_count() > initial_active_threads -                or (not self.expect_greenlet_leak -                    and get_total_main_greenlets() > initial_main_greenlets)): -            sleep(sleep_time) -            if time() > quit_after: -                print("Time limit exceeded.") -                print("Threads: Waiting for only", initial_active_threads, -                      "-->", active_thread_count()) -                print("MGlets : Waiting for only", initial_main_greenlets, -                      "-->", get_total_main_greenlets()) -                break -        collect() - -    def count_objects(self, kind=list, exact_kind=True): -        # pylint:disable=unidiomatic-typecheck -        # Collect the garbage. -        for _ in range(3): -            collect() -        if exact_kind: -            return sum( -                1 -                for x in get_objects() -                if type(x) is kind -            ) -        # instances -        return sum( -            1 -            for x in get_objects() -            if isinstance(x, kind) -        ) - -    greenlets_before_test = 0 -    threads_before_test = 0 -    main_greenlets_before_test = 0 -    expect_greenlet_leak = False - -    def count_greenlets(self): -        """ -        Find all the greenlets and subclasses tracked by the GC. -        """ -        return self.count_objects(RawGreenlet, False) - -    def setUp(self): -        # Ensure the main greenlet exists, otherwise the first test -        # gets a false positive leak -        super().setUp() -        getcurrent() -        self.threads_before_test = active_thread_count() -        self.main_greenlets_before_test = get_total_main_greenlets() -        self.wait_for_pending_cleanups(self.threads_before_test, self.main_greenlets_before_test) -        self.greenlets_before_test = self.count_greenlets() - -    def tearDown(self): -        if getattr(self, 'skipTearDown', False): -            return - -        self.wait_for_pending_cleanups(self.threads_before_test, self.main_greenlets_before_test) -        super().tearDown() - -    def get_expected_returncodes_for_aborted_process(self): -        import signal -        # The child should be aborted in an unusual way. On POSIX -        # platforms, this is done with abort() and signal.SIGABRT, -        # which is reflected in a negative return value; however, on -        # Windows, even though we observe the child print "Fatal -        # Python error: Aborted" and in older versions of the C -        # runtime "This application has requested the Runtime to -        # terminate it in an unusual way," it always has an exit code -        # of 3. This is interesting because 3 is the error code for -        # ERROR_PATH_NOT_FOUND; BUT: the C runtime abort() function -        # also uses this code. -        # -        # If we link to the static C library on Windows, the error -        # code changes to '0xc0000409' (hex(3221226505)), which -        # apparently is STATUS_STACK_BUFFER_OVERRUN; but "What this -        # means is that nowadays when you get a -        # STATUS_STACK_BUFFER_OVERRUN, it doesn’t actually mean that -        # there is a stack buffer overrun. It just means that the -        # application decided to terminate itself with great haste." -        # -        # -        # On windows, we've also seen '0xc0000005' (hex(3221225477)). -        # That's "Access Violation" -        # -        # See -        # https://devblogs.microsoft.com/oldnewthing/20110519-00/?p=10623 -        # and -        # https://docs.microsoft.com/en-us/previous-versions/k089yyh0(v=vs.140)?redirectedfrom=MSDN -        # and -        # https://devblogs.microsoft.com/oldnewthing/20190108-00/?p=100655 -        expected_exit = ( -            -signal.SIGABRT, -            # But beginning on Python 3.11, the faulthandler -            # that prints the C backtraces sometimes segfaults after -            # reporting the exception but before printing the stack. -            # This has only been seen on linux/gcc. -            -signal.SIGSEGV, -        ) if not WIN else ( -            3, -            0xc0000409, -            0xc0000005, -        ) -        return expected_exit - -    def get_process_uss(self): -        """ -        Return the current process's USS in bytes. - -        uss is available on Linux, macOS, Windows. Also known as -        "Unique Set Size", this is the memory which is unique to a -        process and which would be freed if the process was terminated -        right now. - -        If this is not supported by ``psutil``, this raises the -        :exc:`unittest.SkipTest` exception. -        """ -        try: -            return psutil.Process().memory_full_info().uss -        except AttributeError as e: -            raise unittest.SkipTest("uss not supported") from e - -    def run_script(self, script_name, show_output=True): -        import subprocess -        import os -        script = os.path.join( -            os.path.dirname(__file__), -            script_name, -        ) - -        try: -            return subprocess.check_output([sys.executable, script], -                                           encoding='utf-8', -                                           stderr=subprocess.STDOUT) -        except subprocess.CalledProcessError as ex: -            if show_output: -                print('-----') -                print('Failed to run script', script) -                print('~~~~~') -                print(ex.output) -                print('------') -            raise - - -    def assertScriptRaises(self, script_name, exitcodes=None): -        import subprocess -        with self.assertRaises(subprocess.CalledProcessError) as exc: -            output = self.run_script(script_name, show_output=False) -            __traceback_info__ = output -            # We're going to fail the assertion if we get here, at least -            # preserve the output in the traceback. - -        if exitcodes is None: -            exitcodes = self.get_expected_returncodes_for_aborted_process() -        self.assertIn(exc.exception.returncode, exitcodes) -        return exc.exception diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/__init__.cpython-311.pycBinary files differ deleted file mode 100644 index 245565c..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/__init__.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-311.pycBinary files differ deleted file mode 100644 index f8ca571..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_cpp_exception.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_cpp_exception.cpython-311.pycBinary files differ deleted file mode 100644 index 1293a2e..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_cpp_exception.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-311.pycBinary files differ deleted file mode 100644 index 12af9c5..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_slp_switch.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_slp_switch.cpython-311.pycBinary files differ deleted file mode 100644 index 41fa814..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_slp_switch.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-311.pycBinary files differ deleted file mode 100644 index 73d0e65..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-311.pycBinary files differ deleted file mode 100644 index dcdbc02..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-311.pycBinary files differ deleted file mode 100644 index 97be12a..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/leakcheck.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/leakcheck.cpython-311.pycBinary files differ deleted file mode 100644 index 7a2616e..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/leakcheck.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_contextvars.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_contextvars.cpython-311.pycBinary files differ deleted file mode 100644 index afb0e23..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_contextvars.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_cpp.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_cpp.cpython-311.pycBinary files differ deleted file mode 100644 index 3f24186..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_cpp.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_extension_interface.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_extension_interface.cpython-311.pycBinary files differ deleted file mode 100644 index 987e490..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_extension_interface.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_gc.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_gc.cpython-311.pycBinary files differ deleted file mode 100644 index c4edf24..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_gc.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_generator.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_generator.cpython-311.pycBinary files differ deleted file mode 100644 index 936decb..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_generator.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_generator_nested.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_generator_nested.cpython-311.pycBinary files differ deleted file mode 100644 index fa8ca9c..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_generator_nested.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-311.pycBinary files differ deleted file mode 100644 index 6f4f510..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-311.pycBinary files differ deleted file mode 100644 index e40225d..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-311.pycBinary files differ deleted file mode 100644 index 88e931a..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_stack_saved.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_stack_saved.cpython-311.pycBinary files differ deleted file mode 100644 index b3f464d..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_stack_saved.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_throw.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_throw.cpython-311.pycBinary files differ deleted file mode 100644 index 2427360..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_throw.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-311.pycBinary files differ deleted file mode 100644 index a488241..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_version.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_version.cpython-311.pycBinary files differ deleted file mode 100644 index 16d09c1..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_version.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-311.pycBinary files differ deleted file mode 100644 index ba0b403..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension.c b/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension.c deleted file mode 100644 index 05e81c0..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension.c +++ /dev/null @@ -1,231 +0,0 @@ -/* This is a set of functions used by test_extension_interface.py to test the - * Greenlet C API. - */ - -#include "../greenlet.h" - -#ifndef Py_RETURN_NONE -#    define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None -#endif - -#define TEST_MODULE_NAME "_test_extension" - -static PyObject* -test_switch(PyObject* self, PyObject* greenlet) -{ -    PyObject* result = NULL; - -    if (greenlet == NULL || !PyGreenlet_Check(greenlet)) { -        PyErr_BadArgument(); -        return NULL; -    } - -    result = PyGreenlet_Switch((PyGreenlet*)greenlet, NULL, NULL); -    if (result == NULL) { -        if (!PyErr_Occurred()) { -            PyErr_SetString(PyExc_AssertionError, -                            "greenlet.switch() failed for some reason."); -        } -        return NULL; -    } -    Py_INCREF(result); -    return result; -} - -static PyObject* -test_switch_kwargs(PyObject* self, PyObject* args, PyObject* kwargs) -{ -    PyGreenlet* g = NULL; -    PyObject* result = NULL; - -    PyArg_ParseTuple(args, "O!", &PyGreenlet_Type, &g); - -    if (g == NULL || !PyGreenlet_Check(g)) { -        PyErr_BadArgument(); -        return NULL; -    } - -    result = PyGreenlet_Switch(g, NULL, kwargs); -    if (result == NULL) { -        if (!PyErr_Occurred()) { -            PyErr_SetString(PyExc_AssertionError, -                            "greenlet.switch() failed for some reason."); -        } -        return NULL; -    } -    Py_XINCREF(result); -    return result; -} - -static PyObject* -test_getcurrent(PyObject* self) -{ -    PyGreenlet* g = PyGreenlet_GetCurrent(); -    if (g == NULL || !PyGreenlet_Check(g) || !PyGreenlet_ACTIVE(g)) { -        PyErr_SetString(PyExc_AssertionError, -                        "getcurrent() returned an invalid greenlet"); -        Py_XDECREF(g); -        return NULL; -    } -    Py_DECREF(g); -    Py_RETURN_NONE; -} - -static PyObject* -test_setparent(PyObject* self, PyObject* arg) -{ -    PyGreenlet* current; -    PyGreenlet* greenlet = NULL; - -    if (arg == NULL || !PyGreenlet_Check(arg)) { -        PyErr_BadArgument(); -        return NULL; -    } -    if ((current = PyGreenlet_GetCurrent()) == NULL) { -        return NULL; -    } -    greenlet = (PyGreenlet*)arg; -    if (PyGreenlet_SetParent(greenlet, current)) { -        Py_DECREF(current); -        return NULL; -    } -    Py_DECREF(current); -    if (PyGreenlet_Switch(greenlet, NULL, NULL) == NULL) { -        return NULL; -    } -    Py_RETURN_NONE; -} - -static PyObject* -test_new_greenlet(PyObject* self, PyObject* callable) -{ -    PyObject* result = NULL; -    PyGreenlet* greenlet = PyGreenlet_New(callable, NULL); - -    if (!greenlet) { -        return NULL; -    } - -    result = PyGreenlet_Switch(greenlet, NULL, NULL); -    Py_CLEAR(greenlet); -    if (result == NULL) { -        return NULL; -    } - -    Py_INCREF(result); -    return result; -} - -static PyObject* -test_raise_dead_greenlet(PyObject* self) -{ -    PyErr_SetString(PyExc_GreenletExit, "test GreenletExit exception."); -    return NULL; -} - -static PyObject* -test_raise_greenlet_error(PyObject* self) -{ -    PyErr_SetString(PyExc_GreenletError, "test greenlet.error exception"); -    return NULL; -} - -static PyObject* -test_throw(PyObject* self, PyGreenlet* g) -{ -    const char msg[] = "take that sucka!"; -    PyObject* msg_obj = Py_BuildValue("s", msg); -    PyGreenlet_Throw(g, PyExc_ValueError, msg_obj, NULL); -    Py_DECREF(msg_obj); -    if (PyErr_Occurred()) { -        return NULL; -    } -    Py_RETURN_NONE; -} - -static PyObject* -test_throw_exact(PyObject* self, PyObject* args) -{ -    PyGreenlet* g = NULL; -    PyObject* typ = NULL; -    PyObject* val = NULL; -    PyObject* tb = NULL; - -    if (!PyArg_ParseTuple(args, "OOOO:throw", &g, &typ, &val, &tb)) { -        return NULL; -    } - -    PyGreenlet_Throw(g, typ, val, tb); -    if (PyErr_Occurred()) { -        return NULL; -    } -    Py_RETURN_NONE; -} - -static PyMethodDef test_methods[] = { -    {"test_switch", -     (PyCFunction)test_switch, -     METH_O, -     "Switch to the provided greenlet sending provided arguments, and \n" -     "return the results."}, -    {"test_switch_kwargs", -     (PyCFunction)test_switch_kwargs, -     METH_VARARGS | METH_KEYWORDS, -     "Switch to the provided greenlet sending the provided keyword args."}, -    {"test_getcurrent", -     (PyCFunction)test_getcurrent, -     METH_NOARGS, -     "Test PyGreenlet_GetCurrent()"}, -    {"test_setparent", -     (PyCFunction)test_setparent, -     METH_O, -     "Se the parent of the provided greenlet and switch to it."}, -    {"test_new_greenlet", -     (PyCFunction)test_new_greenlet, -     METH_O, -     "Test PyGreenlet_New()"}, -    {"test_raise_dead_greenlet", -     (PyCFunction)test_raise_dead_greenlet, -     METH_NOARGS, -     "Just raise greenlet.GreenletExit"}, -    {"test_raise_greenlet_error", -     (PyCFunction)test_raise_greenlet_error, -     METH_NOARGS, -     "Just raise greenlet.error"}, -    {"test_throw", -     (PyCFunction)test_throw, -     METH_O, -     "Throw a ValueError at the provided greenlet"}, -    {"test_throw_exact", -     (PyCFunction)test_throw_exact, -     METH_VARARGS, -     "Throw exactly the arguments given at the provided greenlet"}, -    {NULL, NULL, 0, NULL} -}; - - -#define INITERROR return NULL - -static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, -                                       TEST_MODULE_NAME, -                                       NULL, -                                       0, -                                       test_methods, -                                       NULL, -                                       NULL, -                                       NULL, -                                       NULL}; - -PyMODINIT_FUNC -PyInit__test_extension(void) -{ -    PyObject* module = NULL; -    module = PyModule_Create(&moduledef); - -    if (module == NULL) { -        return NULL; -    } - -    PyGreenlet_Import(); -    return module; -} diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension.cpython-311-x86_64-linux-gnu.so b/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension.cpython-311-x86_64-linux-gnu.soBinary files differ deleted file mode 100755 index 2c7fff0..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension.cpython-311-x86_64-linux-gnu.so +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpp b/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpp deleted file mode 100644 index 5cbe6a7..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* This is a set of functions used to test C++ exceptions are not - * broken during greenlet switches - */ - -#include "../greenlet.h" -#include "../greenlet_compiler_compat.hpp" -#include <exception> -#include <stdexcept> - -struct exception_t { -    int depth; -    exception_t(int depth) : depth(depth) {} -}; - -/* Functions are called via pointers to prevent inlining */ -static void (*p_test_exception_throw_nonstd)(int depth); -static void (*p_test_exception_throw_std)(); -static PyObject* (*p_test_exception_switch_recurse)(int depth, int left); - -static void -test_exception_throw_nonstd(int depth) -{ -    throw exception_t(depth); -} - -static void -test_exception_throw_std() -{ -    throw std::runtime_error("Thrown from an extension."); -} - -static PyObject* -test_exception_switch_recurse(int depth, int left) -{ -    if (left > 0) { -        return p_test_exception_switch_recurse(depth, left - 1); -    } - -    PyObject* result = NULL; -    PyGreenlet* self = PyGreenlet_GetCurrent(); -    if (self == NULL) -        return NULL; - -    try { -        if (PyGreenlet_Switch(PyGreenlet_GET_PARENT(self), NULL, NULL) == NULL) { -            Py_DECREF(self); -            return NULL; -        } -        p_test_exception_throw_nonstd(depth); -        PyErr_SetString(PyExc_RuntimeError, -                        "throwing C++ exception didn't work"); -    } -    catch (const exception_t& e) { -        if (e.depth != depth) -            PyErr_SetString(PyExc_AssertionError, "depth mismatch"); -        else -            result = PyLong_FromLong(depth); -    } -    catch (...) { -        PyErr_SetString(PyExc_RuntimeError, "unexpected C++ exception"); -    } - -    Py_DECREF(self); -    return result; -} - -/* test_exception_switch(int depth) - * - recurses depth times - * - switches to parent inside try/catch block - * - throws an exception that (expected to be caught in the same function) - * - verifies depth matches (exceptions shouldn't be caught in other greenlets) - */ -static PyObject* -test_exception_switch(PyObject* UNUSED(self), PyObject* args) -{ -    int depth; -    if (!PyArg_ParseTuple(args, "i", &depth)) -        return NULL; -    return p_test_exception_switch_recurse(depth, depth); -} - - -static PyObject* -py_test_exception_throw_nonstd(PyObject* self, PyObject* args) -{ -    if (!PyArg_ParseTuple(args, "")) -        return NULL; -    p_test_exception_throw_nonstd(0); -    PyErr_SetString(PyExc_AssertionError, "unreachable code running after throw"); -    return NULL; -} - -static PyObject* -py_test_exception_throw_std(PyObject* self, PyObject* args) -{ -    if (!PyArg_ParseTuple(args, "")) -        return NULL; -    p_test_exception_throw_std(); -    PyErr_SetString(PyExc_AssertionError, "unreachable code running after throw"); -    return NULL; -} - -static PyObject* -py_test_call(PyObject* self, PyObject* arg) -{ -    PyObject* noargs = PyTuple_New(0); -    PyObject* ret = PyObject_Call(arg, noargs, nullptr); -    Py_DECREF(noargs); -    return ret; -} - - - -/* test_exception_switch_and_do_in_g2(g2func) - * - creates new greenlet g2 to run g2func - * - switches to g2 inside try/catch block - * - verifies that no exception has been caught - * - * it is used together with test_exception_throw to verify that unhandled - * exceptions thrown in one greenlet do not propagate to other greenlet nor - * segfault the process. - */ -static PyObject* -test_exception_switch_and_do_in_g2(PyObject* self, PyObject* args) -{ -    PyObject* g2func = NULL; -    PyObject* result = NULL; - -    if (!PyArg_ParseTuple(args, "O", &g2func)) -        return NULL; -    PyGreenlet* g2 = PyGreenlet_New(g2func, NULL); -    if (!g2) { -        return NULL; -    } - -    try { -        result = PyGreenlet_Switch(g2, NULL, NULL); -        if (!result) { -            return NULL; -        } -    } -    catch (const exception_t& e) { -        /* if we are here the memory can be already corrupted and the program -         * might crash before below py-level exception might become printed. -         * -> print something to stderr to make it clear that we had entered -         *    this catch block. -         * See comments in inner_bootstrap() -         */ -#if defined(WIN32) || defined(_WIN32) -        fprintf(stderr, "C++ exception unexpectedly caught in g1\n"); -        PyErr_SetString(PyExc_AssertionError, "C++ exception unexpectedly caught in g1"); -        Py_XDECREF(result); -        return NULL; -#else -        throw; -#endif -    } - -    Py_XDECREF(result); -    Py_RETURN_NONE; -} - -static PyMethodDef test_methods[] = { -    {"test_exception_switch", -     (PyCFunction)&test_exception_switch, -     METH_VARARGS, -     "Switches to parent twice, to test exception handling and greenlet " -     "switching."}, -    {"test_exception_switch_and_do_in_g2", -     (PyCFunction)&test_exception_switch_and_do_in_g2, -     METH_VARARGS, -     "Creates new greenlet g2 to run g2func and switches to it inside try/catch " -     "block. Used together with test_exception_throw to verify that unhandled " -     "C++ exceptions thrown in a greenlet doe not corrupt memory."}, -    {"test_exception_throw_nonstd", -     (PyCFunction)&py_test_exception_throw_nonstd, -     METH_VARARGS, -     "Throws non-standard C++ exception. Calling this function directly should abort the process." -    }, -    {"test_exception_throw_std", -     (PyCFunction)&py_test_exception_throw_std, -     METH_VARARGS, -     "Throws standard C++ exception. Calling this function directly should abort the process." -    }, -    {"test_call", -     (PyCFunction)&py_test_call, -     METH_O, -     "Call the given callable. Unlike calling it directly, this creates a " -     "new C-level stack frame, which may be helpful in testing." -    }, -    {NULL, NULL, 0, NULL} -}; - - -static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, -                                       "greenlet.tests._test_extension_cpp", -                                       NULL, -                                       0, -                                       test_methods, -                                       NULL, -                                       NULL, -                                       NULL, -                                       NULL}; - -PyMODINIT_FUNC -PyInit__test_extension_cpp(void) -{ -    PyObject* module = NULL; - -    module = PyModule_Create(&moduledef); - -    if (module == NULL) { -        return NULL; -    } - -    PyGreenlet_Import(); -    if (_PyGreenlet_API == NULL) { -        return NULL; -    } - -    p_test_exception_throw_nonstd = test_exception_throw_nonstd; -    p_test_exception_throw_std = test_exception_throw_std; -    p_test_exception_switch_recurse = test_exception_switch_recurse; - -    return module; -} diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpython-311-x86_64-linux-gnu.so b/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpython-311-x86_64-linux-gnu.soBinary files differ deleted file mode 100755 index 714dfa8..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpython-311-x86_64-linux-gnu.so +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/fail_clearing_run_switches.py b/venv/lib/python3.11/site-packages/greenlet/tests/fail_clearing_run_switches.py deleted file mode 100644 index 6dd1492..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/fail_clearing_run_switches.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- -""" -If we have a run callable passed to the constructor or set as an -attribute, but we don't actually use that (because ``__getattribute__`` -or the like interferes), then when we clear callable before beginning -to run, there's an opportunity for Python code to run. - -""" -import greenlet - -g = None -main = greenlet.getcurrent() - -results = [] - -class RunCallable: - -    def __del__(self): -        results.append(('RunCallable', '__del__')) -        main.switch('from RunCallable') - - -class G(greenlet.greenlet): - -    def __getattribute__(self, name): -        if name == 'run': -            results.append(('G.__getattribute__', 'run')) -            return run_func -        return object.__getattribute__(self, name) - - -def run_func(): -    results.append(('run_func', 'enter')) - - -g = G(RunCallable()) -# Try to start G. It will get to the point where it deletes -# its run callable C++ variable in inner_bootstrap. That triggers -# the __del__ method, which switches back to main before g -# actually even starts running. -x = g.switch() -results.append(('main: g.switch()', x)) -# In the C++ code, this results in g->g_switch() appearing to return, even though -# it has yet to run. -print('In main with', x, flush=True) -g.switch() -print('RESULTS', results) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/fail_cpp_exception.py b/venv/lib/python3.11/site-packages/greenlet/tests/fail_cpp_exception.py deleted file mode 100644 index fa4dc2e..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/fail_cpp_exception.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Helper for testing a C++ exception throw aborts the process. - -Takes one argument, the name of the function in :mod:`_test_extension_cpp` to call. -""" -import sys -import greenlet -from greenlet.tests import _test_extension_cpp -print('fail_cpp_exception is running') - -def run_unhandled_exception_in_greenlet_aborts(): -    def _(): -        _test_extension_cpp.test_exception_switch_and_do_in_g2( -            _test_extension_cpp.test_exception_throw_nonstd -        ) -    g1 = greenlet.greenlet(_) -    g1.switch() - - -func_name = sys.argv[1] -try: -    func = getattr(_test_extension_cpp, func_name) -except AttributeError: -    if func_name == run_unhandled_exception_in_greenlet_aborts.__name__: -        func = run_unhandled_exception_in_greenlet_aborts -    elif func_name == 'run_as_greenlet_target': -        g = greenlet.greenlet(_test_extension_cpp.test_exception_throw_std) -        func = g.switch -    else: -        raise -print('raising', func, flush=True) -func() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/fail_initialstub_already_started.py b/venv/lib/python3.11/site-packages/greenlet/tests/fail_initialstub_already_started.py deleted file mode 100644 index c1a44ef..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/fail_initialstub_already_started.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -Testing initialstub throwing an already started exception. -""" - -import greenlet - -a = None -b = None -c = None -main = greenlet.getcurrent() - -# If we switch into a dead greenlet, -# we go looking for its parents. -# if a parent is not yet started, we start it. - -results = [] - -def a_run(*args): -    #results.append('A') -    results.append(('Begin A', args)) - - -def c_run(): -    results.append('Begin C') -    b.switch('From C') -    results.append('C done') - -class A(greenlet.greenlet): pass - -class B(greenlet.greenlet): -    doing_it = False -    def __getattribute__(self, name): -        if name == 'run' and not self.doing_it: -            assert greenlet.getcurrent() is c -            self.doing_it = True -            results.append('Switch to b from B.__getattribute__ in ' -                           + type(greenlet.getcurrent()).__name__) -            b.switch() -            results.append('B.__getattribute__ back from main in ' -                           + type(greenlet.getcurrent()).__name__) -        if name == 'run': -            name = '_B_run' -        return object.__getattribute__(self, name) - -    def _B_run(self, *arg): -        results.append(('Begin B', arg)) -        results.append('_B_run switching to main') -        main.switch('From B') - -class C(greenlet.greenlet): -    pass -a = A(a_run) -b = B(parent=a) -c = C(c_run, b) - -# Start a child; while running, it will start B, -# but starting B will ALSO start B. -result = c.switch() -results.append(('main from c', result)) - -# Switch back to C, which was in the middle of switching -# already. This will throw the ``GreenletStartedWhileInPython`` -# exception, which results in parent A getting started (B is finished) -c.switch() - -results.append(('A dead?', a.dead, 'B dead?', b.dead, 'C dead?', c.dead)) - -# A and B should both be dead now. -assert a.dead -assert b.dead -assert not c.dead - -result = c.switch() -results.append(('main from c.2', result)) -# Now C is dead -assert c.dead - -print("RESULTS:", results) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/fail_slp_switch.py b/venv/lib/python3.11/site-packages/greenlet/tests/fail_slp_switch.py deleted file mode 100644 index 0990526..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/fail_slp_switch.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -""" -A test helper for seeing what happens when slp_switch() -fails. -""" -# pragma: no cover - -import greenlet - - -print('fail_slp_switch is running', flush=True) - -runs = [] -def func(): -    runs.append(1) -    greenlet.getcurrent().parent.switch() -    runs.append(2) -    greenlet.getcurrent().parent.switch() -    runs.append(3) - -g = greenlet._greenlet.UnswitchableGreenlet(func) -g.switch() -assert runs == [1] -g.switch() -assert runs == [1, 2] -g.force_slp_switch_error = True - -# This should crash. -g.switch() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets.py b/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets.py deleted file mode 100644 index e151b19..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Uses a trace function to switch greenlets at unexpected times. - -In the trace function, we switch from the current greenlet to another -greenlet, which switches -""" -import greenlet - -g1 = None -g2 = None - -switch_to_g2 = False - -def tracefunc(*args): -    print('TRACE', *args) -    global switch_to_g2 -    if switch_to_g2: -        switch_to_g2 = False -        g2.switch() -    print('\tLEAVE TRACE', *args) - -def g1_run(): -    print('In g1_run') -    global switch_to_g2 -    switch_to_g2 = True -    from_parent = greenlet.getcurrent().parent.switch() -    print('Return to g1_run') -    print('From parent', from_parent) - -def g2_run(): -    #g1.switch() -    greenlet.getcurrent().parent.switch() - -greenlet.settrace(tracefunc) - -g1 = greenlet.greenlet(g1_run) -g2 = greenlet.greenlet(g2_run) - -# This switch didn't actually finish! -# And if it did, it would raise TypeError -# because g1_run() doesn't take any arguments. -g1.switch(1) -print('Back in main') -g1.switch(2) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets2.py b/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets2.py deleted file mode 100644 index 1f6b66b..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets2.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Like fail_switch_three_greenlets, but the call into g1_run would actually be -valid. -""" -import greenlet - -g1 = None -g2 = None - -switch_to_g2 = True - -results = [] - -def tracefunc(*args): -    results.append(('trace', args[0])) -    print('TRACE', *args) -    global switch_to_g2 -    if switch_to_g2: -        switch_to_g2 = False -        g2.switch('g2 from tracefunc') -    print('\tLEAVE TRACE', *args) - -def g1_run(arg): -    results.append(('g1 arg', arg)) -    print('In g1_run') -    from_parent = greenlet.getcurrent().parent.switch('from g1_run') -    results.append(('g1 from parent', from_parent)) -    return 'g1 done' - -def g2_run(arg): -    #g1.switch() -    results.append(('g2 arg', arg)) -    parent = greenlet.getcurrent().parent.switch('from g2_run') -    global switch_to_g2 -    switch_to_g2 = False -    results.append(('g2 from parent', parent)) -    return 'g2 done' - - -greenlet.settrace(tracefunc) - -g1 = greenlet.greenlet(g1_run) -g2 = greenlet.greenlet(g2_run) - -x = g1.switch('g1 from main') -results.append(('main g1', x)) -print('Back in main', x) -x = g1.switch('g2 from main') -results.append(('main g2', x)) -print('back in amain again', x) -x = g1.switch('g1 from main 2') -results.append(('main g1.2', x)) -x = g2.switch() -results.append(('main g2.2', x)) -print("RESULTS:", results) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_two_greenlets.py b/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_two_greenlets.py deleted file mode 100644 index 3e52345..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_two_greenlets.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Uses a trace function to switch greenlets at unexpected times. - -In the trace function, we switch from the current greenlet to another -greenlet, which switches -""" -import greenlet - -g1 = None -g2 = None - -switch_to_g2 = False - -def tracefunc(*args): -    print('TRACE', *args) -    global switch_to_g2 -    if switch_to_g2: -        switch_to_g2 = False -        g2.switch() -    print('\tLEAVE TRACE', *args) - -def g1_run(): -    print('In g1_run') -    global switch_to_g2 -    switch_to_g2 = True -    greenlet.getcurrent().parent.switch() -    print('Return to g1_run') -    print('Falling off end of g1_run') - -def g2_run(): -    g1.switch() -    print('Falling off end of g2') - -greenlet.settrace(tracefunc) - -g1 = greenlet.greenlet(g1_run) -g2 = greenlet.greenlet(g2_run) - -g1.switch() -print('Falling off end of main') -g2.switch() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/leakcheck.py b/venv/lib/python3.11/site-packages/greenlet/tests/leakcheck.py deleted file mode 100644 index a5152fb..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/leakcheck.py +++ /dev/null @@ -1,319 +0,0 @@ -# Copyright (c) 2018 gevent community -# Copyright (c) 2021 greenlet community -# -# This was originally part of gevent's test suite. The main author -# (Jason Madden) vendored a copy of it into greenlet. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -from __future__ import print_function - -import os -import sys -import gc - -from functools import wraps -import unittest - - -import objgraph - -# graphviz 0.18 (Nov 7 2021), available only on Python 3.6 and newer, -# has added type hints (sigh). It wants to use ``typing.Literal`` for -# some stuff, but that's only available on Python 3.9+. If that's not -# found, it creates a ``unittest.mock.MagicMock`` object and annotates -# with that. These are GC'able objects, and doing almost *anything* -# with them results in an explosion of objects. For example, trying to -# compare them for equality creates new objects. This causes our -# leakchecks to fail, with reports like: -# -# greenlet.tests.leakcheck.LeakCheckError: refcount increased by [337, 1333, 343, 430, 530, 643, 769] -# _Call          1820      +546 -# dict           4094       +76 -# MagicProxy      585       +73 -# tuple          2693       +66 -# _CallList        24        +3 -# weakref        1441        +1 -# function       5996        +1 -# type            736        +1 -# cell            592        +1 -# MagicMock         8        +1 -# -# To avoid this, we *could* filter this type of object out early. In -# principle it could leak, but we don't use mocks in greenlet, so it -# doesn't leak from us. However, a further issue is that ``MagicMock`` -# objects have subobjects that are also GC'able, like ``_Call``, and -# those create new mocks of their own too. So we'd have to filter them -# as well, and they're not public. That's OK, we can workaround the -# problem by being very careful to never compare by equality or other -# user-defined operators, only using object identity or other builtin -# functions. - -RUNNING_ON_GITHUB_ACTIONS = os.environ.get('GITHUB_ACTIONS') -RUNNING_ON_TRAVIS = os.environ.get('TRAVIS') or RUNNING_ON_GITHUB_ACTIONS -RUNNING_ON_APPVEYOR = os.environ.get('APPVEYOR') -RUNNING_ON_CI = RUNNING_ON_TRAVIS or RUNNING_ON_APPVEYOR -RUNNING_ON_MANYLINUX = os.environ.get('GREENLET_MANYLINUX') -SKIP_LEAKCHECKS = RUNNING_ON_MANYLINUX or os.environ.get('GREENLET_SKIP_LEAKCHECKS') -SKIP_FAILING_LEAKCHECKS = os.environ.get('GREENLET_SKIP_FAILING_LEAKCHECKS') -ONLY_FAILING_LEAKCHECKS = os.environ.get('GREENLET_ONLY_FAILING_LEAKCHECKS') - -def ignores_leakcheck(func): -    """ -    Ignore the given object during leakchecks. - -    Can be applied to a method, in which case the method will run, but -    will not be subject to leak checks. - -    If applied to a class, the entire class will be skipped during leakchecks. This -    is intended to be used for classes that are very slow and cause problems such as -    test timeouts; typically it will be used for classes that are subclasses of a base -    class and specify variants of behaviour (such as pool sizes). -    """ -    func.ignore_leakcheck = True -    return func - -def fails_leakcheck(func): -    """ -    Mark that the function is known to leak. -    """ -    func.fails_leakcheck = True -    if SKIP_FAILING_LEAKCHECKS: -        func = unittest.skip("Skipping known failures")(func) -    return func - -class LeakCheckError(AssertionError): -    pass - -if hasattr(sys, 'getobjects'): -    # In a Python build with ``--with-trace-refs``, make objgraph -    # trace *all* the objects, not just those that are tracked by the -    # GC -    class _MockGC(object): -        def get_objects(self): -            return sys.getobjects(0) # pylint:disable=no-member -        def __getattr__(self, name): -            return getattr(gc, name) -    objgraph.gc = _MockGC() -    fails_strict_leakcheck = fails_leakcheck -else: -    def fails_strict_leakcheck(func): -        """ -        Decorator for a function that is known to fail when running -        strict (``sys.getobjects()``) leakchecks. - -        This type of leakcheck finds all objects, even those, such as -        strings, which are not tracked by the garbage collector. -        """ -        return func - -class ignores_types_in_strict_leakcheck(object): -    def __init__(self, types): -        self.types = types -    def __call__(self, func): -        func.leakcheck_ignore_types = self.types -        return func - -class _RefCountChecker(object): - -    # Some builtin things that we ignore -    # XXX: Those things were ignored by gevent, but they're important here, -    # presumably. -    IGNORED_TYPES = () #(tuple, dict, types.FrameType, types.TracebackType) - -    def __init__(self, testcase, function): -        self.testcase = testcase -        self.function = function -        self.deltas = [] -        self.peak_stats = {} -        self.ignored_types = () - -        # The very first time we are called, we have already been -        # self.setUp() by the test runner, so we don't need to do it again. -        self.needs_setUp = False - -    def _include_object_p(self, obj): -        # pylint:disable=too-many-return-statements -        # -        # See the comment block at the top. We must be careful to -        # avoid invoking user-defined operations. -        if obj is self: -            return False -        kind = type(obj) -        # ``self._include_object_p == obj`` returns NotImplemented -        # for non-function objects, which causes the interpreter -        # to try to reverse the order of arguments...which leads -        # to the explosion of mock objects. We don't want that, so we implement -        # the check manually. -        if kind == type(self._include_object_p): -            try: -                # pylint:disable=not-callable -                exact_method_equals = self._include_object_p.__eq__(obj) -            except AttributeError: -                # Python 2.7 methods may only have __cmp__, and that raises a -                # TypeError for non-method arguments -                # pylint:disable=no-member -                exact_method_equals = self._include_object_p.__cmp__(obj) == 0 - -            if exact_method_equals is not NotImplemented and exact_method_equals: -                return False - -        # Similarly, we need to check identity in our __dict__ to avoid mock explosions. -        for x in self.__dict__.values(): -            if obj is x: -                return False - - -        if kind in self.ignored_types or kind in self.IGNORED_TYPES: -            return False - -        return True - -    def _growth(self): -        return objgraph.growth(limit=None, peak_stats=self.peak_stats, -                               filter=self._include_object_p) - -    def _report_diff(self, growth): -        if not growth: -            return "<Unable to calculate growth>" - -        lines = [] -        width = max(len(name) for name, _, _ in growth) -        for name, count, delta in growth: -            lines.append('%-*s%9d %+9d' % (width, name, count, delta)) - -        diff = '\n'.join(lines) -        return diff - - -    def _run_test(self, args, kwargs): -        gc_enabled = gc.isenabled() -        gc.disable() - -        if self.needs_setUp: -            self.testcase.setUp() -            self.testcase.skipTearDown = False -        try: -            self.function(self.testcase, *args, **kwargs) -        finally: -            self.testcase.tearDown() -            self.testcase.doCleanups() -            self.testcase.skipTearDown = True -            self.needs_setUp = True -            if gc_enabled: -                gc.enable() - -    def _growth_after(self): -        # Grab post snapshot -        # pylint:disable=no-member -        if 'urlparse' in sys.modules: -            sys.modules['urlparse'].clear_cache() -        if 'urllib.parse' in sys.modules: -            sys.modules['urllib.parse'].clear_cache() - -        return self._growth() - -    def _check_deltas(self, growth): -        # Return false when we have decided there is no leak, -        # true if we should keep looping, raises an assertion -        # if we have decided there is a leak. - -        deltas = self.deltas -        if not deltas: -            # We haven't run yet, no data, keep looping -            return True - -        if gc.garbage: -            raise LeakCheckError("Generated uncollectable garbage %r" % (gc.garbage,)) - - -        # the following configurations are classified as "no leak" -        # [0, 0] -        # [x, 0, 0] -        # [... a, b, c, d]  where a+b+c+d = 0 -        # -        # the following configurations are classified as "leak" -        # [... z, z, z]  where z > 0 - -        if deltas[-2:] == [0, 0] and len(deltas) in (2, 3): -            return False - -        if deltas[-3:] == [0, 0, 0]: -            return False - -        if len(deltas) >= 4 and sum(deltas[-4:]) == 0: -            return False - -        if len(deltas) >= 3 and deltas[-1] > 0 and deltas[-1] == deltas[-2] and deltas[-2] == deltas[-3]: -            diff = self._report_diff(growth) -            raise LeakCheckError('refcount increased by %r\n%s' % (deltas, diff)) - -        # OK, we don't know for sure yet. Let's search for more -        if sum(deltas[-3:]) <= 0 or sum(deltas[-4:]) <= 0 or deltas[-4:].count(0) >= 2: -            # this is suspicious, so give a few more runs -            limit = 11 -        else: -            limit = 7 -        if len(deltas) >= limit: -            raise LeakCheckError('refcount increased by %r\n%s' -                                 % (deltas, -                                    self._report_diff(growth))) - -        # We couldn't decide yet, keep going -        return True - -    def __call__(self, args, kwargs): -        for _ in range(3): -            gc.collect() - -        expect_failure = getattr(self.function, 'fails_leakcheck', False) -        if expect_failure: -            self.testcase.expect_greenlet_leak = True -        self.ignored_types = getattr(self.function, "leakcheck_ignore_types", ()) - -        # Capture state before; the incremental will be -        # updated by each call to _growth_after -        growth = self._growth() - -        try: -            while self._check_deltas(growth): -                self._run_test(args, kwargs) - -                growth = self._growth_after() - -                self.deltas.append(sum((stat[2] for stat in growth))) -        except LeakCheckError: -            if not expect_failure: -                raise -        else: -            if expect_failure: -                raise LeakCheckError("Expected %s to leak but it did not." % (self.function,)) - -def wrap_refcount(method): -    if getattr(method, 'ignore_leakcheck', False) or SKIP_LEAKCHECKS: -        return method - -    @wraps(method) -    def wrapper(self, *args, **kwargs): # pylint:disable=too-many-branches -        if getattr(self, 'ignore_leakcheck', False): -            raise unittest.SkipTest("This class ignored during leakchecks") -        if ONLY_FAILING_LEAKCHECKS and not getattr(method, 'fails_leakcheck', False): -            raise unittest.SkipTest("Only running tests that fail leakchecks.") -        return _RefCountChecker(self, method)(args, kwargs) - -    return wrapper diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_contextvars.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_contextvars.py deleted file mode 100644 index 9a16f67..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_contextvars.py +++ /dev/null @@ -1,310 +0,0 @@ -from __future__ import print_function - -import gc -import sys -import unittest - -from functools import partial -from unittest import skipUnless -from unittest import skipIf - -from greenlet import greenlet -from greenlet import getcurrent -from . import TestCase - - -try: -    from contextvars import Context -    from contextvars import ContextVar -    from contextvars import copy_context -    # From the documentation: -    # -    # Important: Context Variables should be created at the top module -    # level and never in closures. Context objects hold strong -    # references to context variables which prevents context variables -    # from being properly garbage collected. -    ID_VAR = ContextVar("id", default=None) -    VAR_VAR = ContextVar("var", default=None) -    ContextVar = None -except ImportError: -    Context = ContextVar = copy_context = None - -# We don't support testing if greenlet's built-in context var support is disabled. -@skipUnless(Context is not None, "ContextVar not supported") -class ContextVarsTests(TestCase): -    def _new_ctx_run(self, *args, **kwargs): -        return copy_context().run(*args, **kwargs) - -    def _increment(self, greenlet_id, callback, counts, expect): -        ctx_var = ID_VAR -        if expect is None: -            self.assertIsNone(ctx_var.get()) -        else: -            self.assertEqual(ctx_var.get(), expect) -        ctx_var.set(greenlet_id) -        for _ in range(2): -            counts[ctx_var.get()] += 1 -            callback() - -    def _test_context(self, propagate_by): -        # pylint:disable=too-many-branches -        ID_VAR.set(0) - -        callback = getcurrent().switch -        counts = dict((i, 0) for i in range(5)) - -        lets = [ -            greenlet(partial( -                partial( -                    copy_context().run, -                    self._increment -                ) if propagate_by == "run" else self._increment, -                greenlet_id=i, -                callback=callback, -                counts=counts, -                expect=( -                    i - 1 if propagate_by == "share" else -                    0 if propagate_by in ("set", "run") else None -                ) -            )) -            for i in range(1, 5) -        ] - -        for let in lets: -            if propagate_by == "set": -                let.gr_context = copy_context() -            elif propagate_by == "share": -                let.gr_context = getcurrent().gr_context - -        for i in range(2): -            counts[ID_VAR.get()] += 1 -            for let in lets: -                let.switch() - -        if propagate_by == "run": -            # Must leave each context.run() in reverse order of entry -            for let in reversed(lets): -                let.switch() -        else: -            # No context.run(), so fine to exit in any order. -            for let in lets: -                let.switch() - -        for let in lets: -            self.assertTrue(let.dead) -            # When using run(), we leave the run() as the greenlet dies, -            # and there's no context "underneath". When not using run(), -            # gr_context still reflects the context the greenlet was -            # running in. -            if propagate_by == 'run': -                self.assertIsNone(let.gr_context) -            else: -                self.assertIsNotNone(let.gr_context) - - -        if propagate_by == "share": -            self.assertEqual(counts, {0: 1, 1: 1, 2: 1, 3: 1, 4: 6}) -        else: -            self.assertEqual(set(counts.values()), set([2])) - -    def test_context_propagated_by_context_run(self): -        self._new_ctx_run(self._test_context, "run") - -    def test_context_propagated_by_setting_attribute(self): -        self._new_ctx_run(self._test_context, "set") - -    def test_context_not_propagated(self): -        self._new_ctx_run(self._test_context, None) - -    def test_context_shared(self): -        self._new_ctx_run(self._test_context, "share") - -    def test_break_ctxvars(self): -        let1 = greenlet(copy_context().run) -        let2 = greenlet(copy_context().run) -        let1.switch(getcurrent().switch) -        let2.switch(getcurrent().switch) -        # Since let2 entered the current context and let1 exits its own, the -        # interpreter emits: -        # RuntimeError: cannot exit context: thread state references a different context object -        let1.switch() - -    def test_not_broken_if_using_attribute_instead_of_context_run(self): -        let1 = greenlet(getcurrent().switch) -        let2 = greenlet(getcurrent().switch) -        let1.gr_context = copy_context() -        let2.gr_context = copy_context() -        let1.switch() -        let2.switch() -        let1.switch() -        let2.switch() - -    def test_context_assignment_while_running(self): -        # pylint:disable=too-many-statements -        ID_VAR.set(None) - -        def target(): -            self.assertIsNone(ID_VAR.get()) -            self.assertIsNone(gr.gr_context) - -            # Context is created on first use -            ID_VAR.set(1) -            self.assertIsInstance(gr.gr_context, Context) -            self.assertEqual(ID_VAR.get(), 1) -            self.assertEqual(gr.gr_context[ID_VAR], 1) - -            # Clearing the context makes it get re-created as another -            # empty context when next used -            old_context = gr.gr_context -            gr.gr_context = None  # assign None while running -            self.assertIsNone(ID_VAR.get()) -            self.assertIsNone(gr.gr_context) -            ID_VAR.set(2) -            self.assertIsInstance(gr.gr_context, Context) -            self.assertEqual(ID_VAR.get(), 2) -            self.assertEqual(gr.gr_context[ID_VAR], 2) - -            new_context = gr.gr_context -            getcurrent().parent.switch((old_context, new_context)) -            # parent switches us back to old_context - -            self.assertEqual(ID_VAR.get(), 1) -            gr.gr_context = new_context  # assign non-None while running -            self.assertEqual(ID_VAR.get(), 2) - -            getcurrent().parent.switch() -            # parent switches us back to no context -            self.assertIsNone(ID_VAR.get()) -            self.assertIsNone(gr.gr_context) -            gr.gr_context = old_context -            self.assertEqual(ID_VAR.get(), 1) - -            getcurrent().parent.switch() -            # parent switches us back to no context -            self.assertIsNone(ID_VAR.get()) -            self.assertIsNone(gr.gr_context) - -        gr = greenlet(target) - -        with self.assertRaisesRegex(AttributeError, "can't delete context attribute"): -            del gr.gr_context - -        self.assertIsNone(gr.gr_context) -        old_context, new_context = gr.switch() -        self.assertIs(new_context, gr.gr_context) -        self.assertEqual(old_context[ID_VAR], 1) -        self.assertEqual(new_context[ID_VAR], 2) -        self.assertEqual(new_context.run(ID_VAR.get), 2) -        gr.gr_context = old_context  # assign non-None while suspended -        gr.switch() -        self.assertIs(gr.gr_context, new_context) -        gr.gr_context = None  # assign None while suspended -        gr.switch() -        self.assertIs(gr.gr_context, old_context) -        gr.gr_context = None -        gr.switch() -        self.assertIsNone(gr.gr_context) - -        # Make sure there are no reference leaks -        gr = None -        gc.collect() -        self.assertEqual(sys.getrefcount(old_context), 2) -        self.assertEqual(sys.getrefcount(new_context), 2) - -    def test_context_assignment_different_thread(self): -        import threading -        VAR_VAR.set(None) -        ctx = Context() - -        is_running = threading.Event() -        should_suspend = threading.Event() -        did_suspend = threading.Event() -        should_exit = threading.Event() -        holder = [] - -        def greenlet_in_thread_fn(): -            VAR_VAR.set(1) -            is_running.set() -            should_suspend.wait(10) -            VAR_VAR.set(2) -            getcurrent().parent.switch() -            holder.append(VAR_VAR.get()) - -        def thread_fn(): -            gr = greenlet(greenlet_in_thread_fn) -            gr.gr_context = ctx -            holder.append(gr) -            gr.switch() -            did_suspend.set() -            should_exit.wait(10) -            gr.switch() -            del gr -            greenlet() # trigger cleanup - -        thread = threading.Thread(target=thread_fn, daemon=True) -        thread.start() -        is_running.wait(10) -        gr = holder[0] - -        # Can't access or modify context if the greenlet is running -        # in a different thread -        with self.assertRaisesRegex(ValueError, "running in a different"): -            getattr(gr, 'gr_context') -        with self.assertRaisesRegex(ValueError, "running in a different"): -            gr.gr_context = None - -        should_suspend.set() -        did_suspend.wait(10) - -        # OK to access and modify context if greenlet is suspended -        self.assertIs(gr.gr_context, ctx) -        self.assertEqual(gr.gr_context[VAR_VAR], 2) -        gr.gr_context = None - -        should_exit.set() -        thread.join(10) - -        self.assertEqual(holder, [gr, None]) - -        # Context can still be accessed/modified when greenlet is dead: -        self.assertIsNone(gr.gr_context) -        gr.gr_context = ctx -        self.assertIs(gr.gr_context, ctx) - -        # Otherwise we leak greenlets on some platforms. -        # XXX: Should be able to do this automatically -        del holder[:] -        gr = None -        thread = None - -    def test_context_assignment_wrong_type(self): -        g = greenlet() -        with self.assertRaisesRegex(TypeError, -                                    "greenlet context must be a contextvars.Context or None"): -            g.gr_context = self - - -@skipIf(Context is not None, "ContextVar supported") -class NoContextVarsTests(TestCase): -    def test_contextvars_errors(self): -        let1 = greenlet(getcurrent().switch) -        self.assertFalse(hasattr(let1, 'gr_context')) -        with self.assertRaises(AttributeError): -            getattr(let1, 'gr_context') - -        with self.assertRaises(AttributeError): -            let1.gr_context = None - -        let1.switch() - -        with self.assertRaises(AttributeError): -            getattr(let1, 'gr_context') - -        with self.assertRaises(AttributeError): -            let1.gr_context = None - -        del let1 - - -if __name__ == '__main__': -    unittest.main() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_cpp.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_cpp.py deleted file mode 100644 index 2d0cc9c..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_cpp.py +++ /dev/null @@ -1,73 +0,0 @@ -from __future__ import print_function -from __future__ import absolute_import - -import subprocess -import unittest - -import greenlet -from . import _test_extension_cpp -from . import TestCase -from . import WIN - -class CPPTests(TestCase): -    def test_exception_switch(self): -        greenlets = [] -        for i in range(4): -            g = greenlet.greenlet(_test_extension_cpp.test_exception_switch) -            g.switch(i) -            greenlets.append(g) -        for i, g in enumerate(greenlets): -            self.assertEqual(g.switch(), i) - -    def _do_test_unhandled_exception(self, target): -        import os -        import sys -        script = os.path.join( -            os.path.dirname(__file__), -            'fail_cpp_exception.py', -        ) -        args = [sys.executable, script, target.__name__ if not isinstance(target, str) else target] -        __traceback_info__ = args -        with self.assertRaises(subprocess.CalledProcessError) as exc: -            subprocess.check_output( -                args, -                encoding='utf-8', -                stderr=subprocess.STDOUT -            ) - -        ex = exc.exception -        expected_exit = self.get_expected_returncodes_for_aborted_process() -        self.assertIn(ex.returncode, expected_exit) -        self.assertIn('fail_cpp_exception is running', ex.output) -        return ex.output - - -    def test_unhandled_nonstd_exception_aborts(self): -        # verify that plain unhandled throw aborts -        self._do_test_unhandled_exception(_test_extension_cpp.test_exception_throw_nonstd) - -    def test_unhandled_std_exception_aborts(self): -        # verify that plain unhandled throw aborts -        self._do_test_unhandled_exception(_test_extension_cpp.test_exception_throw_std) - -    @unittest.skipIf(WIN, "XXX: This does not crash on Windows") -    # Meaning the exception is getting lost somewhere... -    def test_unhandled_std_exception_as_greenlet_function_aborts(self): -        # verify that plain unhandled throw aborts -        output = self._do_test_unhandled_exception('run_as_greenlet_target') -        self.assertIn( -            # We really expect this to be prefixed with "greenlet: Unhandled C++ exception:" -            # as added by our handler for std::exception (see TUserGreenlet.cpp), but -            # that's not correct everywhere --- our handler never runs before std::terminate -            # gets called (for example, on arm32). -            'Thrown from an extension.', -            output -        ) - -    def test_unhandled_exception_in_greenlet_aborts(self): -        # verify that unhandled throw called in greenlet aborts too -        self._do_test_unhandled_exception('run_unhandled_exception_in_greenlet_aborts') - - -if __name__ == '__main__': -    unittest.main() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_extension_interface.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_extension_interface.py deleted file mode 100644 index 34b6656..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_extension_interface.py +++ /dev/null @@ -1,115 +0,0 @@ -from __future__ import print_function -from __future__ import absolute_import - -import sys - -import greenlet -from . import _test_extension -from . import TestCase - -# pylint:disable=c-extension-no-member - -class CAPITests(TestCase): -    def test_switch(self): -        self.assertEqual( -            50, _test_extension.test_switch(greenlet.greenlet(lambda: 50))) - -    def test_switch_kwargs(self): -        def adder(x, y): -            return x * y -        g = greenlet.greenlet(adder) -        self.assertEqual(6, _test_extension.test_switch_kwargs(g, x=3, y=2)) - -    def test_setparent(self): -        # pylint:disable=disallowed-name -        def foo(): -            def bar(): -                greenlet.getcurrent().parent.switch() - -                # This final switch should go back to the main greenlet, since -                # the test_setparent() function in the C extension should have -                # reparented this greenlet. -                greenlet.getcurrent().parent.switch() -                raise AssertionError("Should never have reached this code") -            child = greenlet.greenlet(bar) -            child.switch() -            greenlet.getcurrent().parent.switch(child) -            greenlet.getcurrent().parent.throw( -                AssertionError("Should never reach this code")) -        foo_child = greenlet.greenlet(foo).switch() -        self.assertEqual(None, _test_extension.test_setparent(foo_child)) - -    def test_getcurrent(self): -        _test_extension.test_getcurrent() - -    def test_new_greenlet(self): -        self.assertEqual(-15, _test_extension.test_new_greenlet(lambda: -15)) - -    def test_raise_greenlet_dead(self): -        self.assertRaises( -            greenlet.GreenletExit, _test_extension.test_raise_dead_greenlet) - -    def test_raise_greenlet_error(self): -        self.assertRaises( -            greenlet.error, _test_extension.test_raise_greenlet_error) - -    def test_throw(self): -        seen = [] - -        def foo():         # pylint:disable=disallowed-name -            try: -                greenlet.getcurrent().parent.switch() -            except ValueError: -                seen.append(sys.exc_info()[1]) -            except greenlet.GreenletExit: -                raise AssertionError -        g = greenlet.greenlet(foo) -        g.switch() -        _test_extension.test_throw(g) -        self.assertEqual(len(seen), 1) -        self.assertTrue( -            isinstance(seen[0], ValueError), -            "ValueError was not raised in foo()") -        self.assertEqual( -            str(seen[0]), -            'take that sucka!', -            "message doesn't match") - -    def test_non_traceback_param(self): -        with self.assertRaises(TypeError) as exc: -            _test_extension.test_throw_exact( -                greenlet.getcurrent(), -                Exception, -                Exception(), -                self -            ) -        self.assertEqual(str(exc.exception), -                         "throw() third argument must be a traceback object") - -    def test_instance_of_wrong_type(self): -        with self.assertRaises(TypeError) as exc: -            _test_extension.test_throw_exact( -                greenlet.getcurrent(), -                Exception(), -                BaseException(), -                None, -            ) - -        self.assertEqual(str(exc.exception), -                         "instance exception may not have a separate value") - -    def test_not_throwable(self): -        with self.assertRaises(TypeError) as exc: -            _test_extension.test_throw_exact( -                greenlet.getcurrent(), -                "abc", -                None, -                None, -            ) -        self.assertEqual(str(exc.exception), -                         "exceptions must be classes, or instances, not str") - - -if __name__ == '__main__': -    import unittest -    unittest.main() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_gc.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_gc.py deleted file mode 100644 index 994addb..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_gc.py +++ /dev/null @@ -1,86 +0,0 @@ -import gc - -import weakref - -import greenlet - - -from . import TestCase -from .leakcheck import fails_leakcheck -# These only work with greenlet gc support -# which is no longer optional. -assert greenlet.GREENLET_USE_GC - -class GCTests(TestCase): -    def test_dead_circular_ref(self): -        o = weakref.ref(greenlet.greenlet(greenlet.getcurrent).switch()) -        gc.collect() -        if o() is not None: -            import sys -            print("O IS NOT NONE.", sys.getrefcount(o())) -        self.assertIsNone(o()) -        self.assertFalse(gc.garbage, gc.garbage) - -    def test_circular_greenlet(self): -        class circular_greenlet(greenlet.greenlet): -            self = None -        o = circular_greenlet() -        o.self = o -        o = weakref.ref(o) -        gc.collect() -        self.assertIsNone(o()) -        self.assertFalse(gc.garbage, gc.garbage) - -    def test_inactive_ref(self): -        class inactive_greenlet(greenlet.greenlet): -            def __init__(self): -                greenlet.greenlet.__init__(self, run=self.run) - -            def run(self): -                pass -        o = inactive_greenlet() -        o = weakref.ref(o) -        gc.collect() -        self.assertIsNone(o()) -        self.assertFalse(gc.garbage, gc.garbage) - -    @fails_leakcheck -    def test_finalizer_crash(self): -        # This test is designed to crash when active greenlets -        # are made garbage collectable, until the underlying -        # problem is resolved. How does it work: -        # - order of object creation is important -        # - array is created first, so it is moved to unreachable first -        # - we create a cycle between a greenlet and this array -        # - we create an object that participates in gc, is only -        #   referenced by a greenlet, and would corrupt gc lists -        #   on destruction, the easiest is to use an object with -        #   a finalizer -        # - because array is the first object in unreachable it is -        #   cleared first, which causes all references to greenlet -        #   to disappear and causes greenlet to be destroyed, but since -        #   it is still live it causes a switch during gc, which causes -        #   an object with finalizer to be destroyed, which causes stack -        #   corruption and then a crash - -        class object_with_finalizer(object): -            def __del__(self): -                pass -        array = [] -        parent = greenlet.getcurrent() -        def greenlet_body(): -            greenlet.getcurrent().object = object_with_finalizer() -            try: -                parent.switch() -            except greenlet.GreenletExit: -                print("Got greenlet exit!") -            finally: -                del greenlet.getcurrent().object -        g = greenlet.greenlet(greenlet_body) -        g.array = array -        array.append(g) -        g.switch() -        del array -        del g -        greenlet.getcurrent() -        gc.collect() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_generator.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_generator.py deleted file mode 100644 index ca4a644..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_generator.py +++ /dev/null @@ -1,59 +0,0 @@ - -from greenlet import greenlet - -from . import TestCase - -class genlet(greenlet): -    parent = None -    def __init__(self, *args, **kwds): -        self.args = args -        self.kwds = kwds - -    def run(self): -        fn, = self.fn -        fn(*self.args, **self.kwds) - -    def __iter__(self): -        return self - -    def __next__(self): -        self.parent = greenlet.getcurrent() -        result = self.switch() -        if self: -            return result - -        raise StopIteration - -    next = __next__ - - -def Yield(value): -    g = greenlet.getcurrent() -    while not isinstance(g, genlet): -        if g is None: -            raise RuntimeError('yield outside a genlet') -        g = g.parent -    g.parent.switch(value) - - -def generator(func): -    class Generator(genlet): -        fn = (func,) -    return Generator - -# ____________________________________________________________ - - -class GeneratorTests(TestCase): -    def test_generator(self): -        seen = [] - -        def g(n): -            for i in range(n): -                seen.append(i) -                Yield(i) -        g = generator(g) -        for _ in range(3): -            for j in g(5): -                seen.append(j) -        self.assertEqual(seen, 3 * [0, 0, 1, 1, 2, 2, 3, 3, 4, 4]) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_generator_nested.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_generator_nested.py deleted file mode 100644 index 8d752a6..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_generator_nested.py +++ /dev/null @@ -1,168 +0,0 @@ - -from greenlet import greenlet -from . import TestCase -from .leakcheck import fails_leakcheck - -class genlet(greenlet): -    parent = None -    def __init__(self, *args, **kwds): -        self.args = args -        self.kwds = kwds -        self.child = None - -    def run(self): -        # Note the function is packed in a tuple -        # to avoid creating a bound method for it. -        fn, = self.fn -        fn(*self.args, **self.kwds) - -    def __iter__(self): -        return self - -    def set_child(self, child): -        self.child = child - -    def __next__(self): -        if self.child: -            child = self.child -            while child.child: -                tmp = child -                child = child.child -                tmp.child = None - -            result = child.switch() -        else: -            self.parent = greenlet.getcurrent() -            result = self.switch() - -        if self: -            return result - -        raise StopIteration - -    next = __next__ - -def Yield(value, level=1): -    g = greenlet.getcurrent() - -    while level != 0: -        if not isinstance(g, genlet): -            raise RuntimeError('yield outside a genlet') -        if level > 1: -            g.parent.set_child(g) -        g = g.parent -        level -= 1 - -    g.switch(value) - - -def Genlet(func): -    class TheGenlet(genlet): -        fn = (func,) -    return TheGenlet - -# ____________________________________________________________ - - -def g1(n, seen): -    for i in range(n): -        seen.append(i + 1) -        yield i - - -def g2(n, seen): -    for i in range(n): -        seen.append(i + 1) -        Yield(i) - -g2 = Genlet(g2) - - -def nested(i): -    Yield(i) - - -def g3(n, seen): -    for i in range(n): -        seen.append(i + 1) -        nested(i) -g3 = Genlet(g3) - - -def a(n): -    if n == 0: -        return -    for ii in ax(n - 1): -        Yield(ii) -    Yield(n) -ax = Genlet(a) - - -def perms(l): -    if len(l) > 1: -        for e in l: -            # No syntactical sugar for generator expressions -            x = [Yield([e] + p) for p in perms([x for x in l if x != e])] -            assert x -    else: -        Yield(l) -perms = Genlet(perms) - - -def gr1(n): -    for ii in range(1, n): -        Yield(ii) -        Yield(ii * ii, 2) - -gr1 = Genlet(gr1) - - -def gr2(n, seen): -    for ii in gr1(n): -        seen.append(ii) - -gr2 = Genlet(gr2) - - -class NestedGeneratorTests(TestCase): -    def test_layered_genlets(self): -        seen = [] -        for ii in gr2(5, seen): -            seen.append(ii) -        self.assertEqual(seen, [1, 1, 2, 4, 3, 9, 4, 16]) - -    @fails_leakcheck -    def test_permutations(self): -        gen_perms = perms(list(range(4))) -        permutations = list(gen_perms) -        self.assertEqual(len(permutations), 4 * 3 * 2 * 1) -        self.assertIn([0, 1, 2, 3], permutations) -        self.assertIn([3, 2, 1, 0], permutations) -        res = [] -        for ii in zip(perms(list(range(4))), perms(list(range(3)))): -            res.append(ii) -        self.assertEqual( -            res, -            [([0, 1, 2, 3], [0, 1, 2]), ([0, 1, 3, 2], [0, 2, 1]), -             ([0, 2, 1, 3], [1, 0, 2]), ([0, 2, 3, 1], [1, 2, 0]), -             ([0, 3, 1, 2], [2, 0, 1]), ([0, 3, 2, 1], [2, 1, 0])]) -        # XXX Test to make sure we are working as a generator expression - -    def test_genlet_simple(self): -        for g in g1, g2, g3: -            seen = [] -            for _ in range(3): -                for j in g(5, seen): -                    seen.append(j) -            self.assertEqual(seen, 3 * [1, 0, 2, 1, 3, 2, 4, 3, 5, 4]) - -    def test_genlet_bad(self): -        try: -            Yield(10) -        except RuntimeError: -            pass - -    def test_nested_genlets(self): -        seen = [] -        for ii in ax(5): -            seen.append(ii) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_greenlet.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_greenlet.py deleted file mode 100644 index 51849cd..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_greenlet.py +++ /dev/null @@ -1,1311 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import gc -import sys -import time -import threading - -from abc import ABCMeta, abstractmethod - -import greenlet -from greenlet import greenlet as RawGreenlet -from . import TestCase -from .leakcheck import fails_leakcheck - - -# We manually manage locks in many tests -# pylint:disable=consider-using-with -# pylint:disable=too-many-public-methods -# This module is quite large. -# TODO: Refactor into separate test files. For example, -# put all the regression tests that used to produce -# crashes in test_greenlet_no_crash; put tests that DO deliberately crash -# the interpreter into test_greenlet_crash. -# pylint:disable=too-many-lines - -class SomeError(Exception): -    pass - - -def fmain(seen): -    try: -        greenlet.getcurrent().parent.switch() -    except: -        seen.append(sys.exc_info()[0]) -        raise -    raise SomeError - - -def send_exception(g, exc): -    # note: send_exception(g, exc)  can be now done with  g.throw(exc). -    # the purpose of this test is to explicitly check the propagation rules. -    def crasher(exc): -        raise exc -    g1 = RawGreenlet(crasher, parent=g) -    g1.switch(exc) - - -class TestGreenlet(TestCase): - -    def _do_simple_test(self): -        lst = [] - -        def f(): -            lst.append(1) -            greenlet.getcurrent().parent.switch() -            lst.append(3) -        g = RawGreenlet(f) -        lst.append(0) -        g.switch() -        lst.append(2) -        g.switch() -        lst.append(4) -        self.assertEqual(lst, list(range(5))) - -    def test_simple(self): -        self._do_simple_test() - -    def test_switch_no_run_raises_AttributeError(self): -        g = RawGreenlet() -        with self.assertRaises(AttributeError) as exc: -            g.switch() - -        self.assertIn("run", str(exc.exception)) - -    def test_throw_no_run_raises_AttributeError(self): -        g = RawGreenlet() -        with self.assertRaises(AttributeError) as exc: -            g.throw(SomeError) - -        self.assertIn("run", str(exc.exception)) - -    def test_parent_equals_None(self): -        g = RawGreenlet(parent=None) -        self.assertIsNotNone(g) -        self.assertIs(g.parent, greenlet.getcurrent()) - -    def test_run_equals_None(self): -        g = RawGreenlet(run=None) -        self.assertIsNotNone(g) -        self.assertIsNone(g.run) - -    def test_two_children(self): -        lst = [] - -        def f(): -            lst.append(1) -            greenlet.getcurrent().parent.switch() -            lst.extend([1, 1]) -        g = RawGreenlet(f) -        h = RawGreenlet(f) -        g.switch() -        self.assertEqual(len(lst), 1) -        h.switch() -        self.assertEqual(len(lst), 2) -        h.switch() -        self.assertEqual(len(lst), 4) -        self.assertEqual(h.dead, True) -        g.switch() -        self.assertEqual(len(lst), 6) -        self.assertEqual(g.dead, True) - -    def test_two_recursive_children(self): -        lst = [] - -        def f(): -            lst.append('b') -            greenlet.getcurrent().parent.switch() - -        def g(): -            lst.append('a') -            g = RawGreenlet(f) -            g.switch() -            lst.append('c') - -        g = RawGreenlet(g) -        self.assertEqual(sys.getrefcount(g), 2) -        g.switch() -        self.assertEqual(lst, ['a', 'b', 'c']) -        # Just the one in this frame, plus the one on the stack we pass to the function -        self.assertEqual(sys.getrefcount(g), 2) - -    def test_threads(self): -        success = [] - -        def f(): -            self._do_simple_test() -            success.append(True) -        ths = [threading.Thread(target=f) for i in range(10)] -        for th in ths: -            th.start() -        for th in ths: -            th.join(10) -        self.assertEqual(len(success), len(ths)) - -    def test_exception(self): -        seen = [] -        g1 = RawGreenlet(fmain) -        g2 = RawGreenlet(fmain) -        g1.switch(seen) -        g2.switch(seen) -        g2.parent = g1 - -        self.assertEqual(seen, []) -        #with self.assertRaises(SomeError): -        #    p("***Switching back") -        #    g2.switch() -        # Creating this as a bound method can reveal bugs that -        # are hidden on newer versions of Python that avoid creating -        # bound methods for direct expressions; IOW, don't use the `with` -        # form! -        self.assertRaises(SomeError, g2.switch) -        self.assertEqual(seen, [SomeError]) - -        value = g2.switch() -        self.assertEqual(value, ()) -        self.assertEqual(seen, [SomeError]) - -        value = g2.switch(25) -        self.assertEqual(value, 25) -        self.assertEqual(seen, [SomeError]) - - -    def test_send_exception(self): -        seen = [] -        g1 = RawGreenlet(fmain) -        g1.switch(seen) -        self.assertRaises(KeyError, send_exception, g1, KeyError) -        self.assertEqual(seen, [KeyError]) - -    def test_dealloc(self): -        seen = [] -        g1 = RawGreenlet(fmain) -        g2 = RawGreenlet(fmain) -        g1.switch(seen) -        g2.switch(seen) -        self.assertEqual(seen, []) -        del g1 -        gc.collect() -        self.assertEqual(seen, [greenlet.GreenletExit]) -        del g2 -        gc.collect() -        self.assertEqual(seen, [greenlet.GreenletExit, greenlet.GreenletExit]) - -    def test_dealloc_catches_GreenletExit_throws_other(self): -        def run(): -            try: -                greenlet.getcurrent().parent.switch() -            except greenlet.GreenletExit: -                raise SomeError from None - -        g = RawGreenlet(run) -        g.switch() -        # Destroying the only reference to the greenlet causes it -        # to get GreenletExit; when it in turn raises, even though we're the parent -        # we don't get the exception, it just gets printed. -        # When we run on 3.8 only, we can use sys.unraisablehook -        oldstderr = sys.stderr -        try: -            from cStringIO import StringIO -        except ImportError: -            from io import StringIO -        stderr = sys.stderr = StringIO() -        try: -            del g -        finally: -            sys.stderr = oldstderr - -        v = stderr.getvalue() -        self.assertIn("Exception", v) -        self.assertIn('ignored', v) -        self.assertIn("SomeError", v) - - -    def test_dealloc_other_thread(self): -        seen = [] -        someref = [] - -        bg_glet_created_running_and_no_longer_ref_in_bg = threading.Event() -        fg_ref_released = threading.Event() -        bg_should_be_clear = threading.Event() -        ok_to_exit_bg_thread = threading.Event() - -        def f(): -            g1 = RawGreenlet(fmain) -            g1.switch(seen) -            someref.append(g1) -            del g1 -            gc.collect() - -            bg_glet_created_running_and_no_longer_ref_in_bg.set() -            fg_ref_released.wait(3) - -            RawGreenlet()   # trigger release -            bg_should_be_clear.set() -            ok_to_exit_bg_thread.wait(3) -            RawGreenlet() # One more time - -        t = threading.Thread(target=f) -        t.start() -        bg_glet_created_running_and_no_longer_ref_in_bg.wait(10) - -        self.assertEqual(seen, []) -        self.assertEqual(len(someref), 1) -        del someref[:] -        gc.collect() -        # g1 is not released immediately because it's from another thread -        self.assertEqual(seen, []) -        fg_ref_released.set() -        bg_should_be_clear.wait(3) -        try: -            self.assertEqual(seen, [greenlet.GreenletExit]) -        finally: -            ok_to_exit_bg_thread.set() -            t.join(10) -            del seen[:] -            del someref[:] - -    def test_frame(self): -        def f1(): -            f = sys._getframe(0) # pylint:disable=protected-access -            self.assertEqual(f.f_back, None) -            greenlet.getcurrent().parent.switch(f) -            return "meaning of life" -        g = RawGreenlet(f1) -        frame = g.switch() -        self.assertTrue(frame is g.gr_frame) -        self.assertTrue(g) - -        from_g = g.switch() -        self.assertFalse(g) -        self.assertEqual(from_g, 'meaning of life') -        self.assertEqual(g.gr_frame, None) - -    def test_thread_bug(self): -        def runner(x): -            g = RawGreenlet(lambda: time.sleep(x)) -            g.switch() -        t1 = threading.Thread(target=runner, args=(0.2,)) -        t2 = threading.Thread(target=runner, args=(0.3,)) -        t1.start() -        t2.start() -        t1.join(10) -        t2.join(10) - -    def test_switch_kwargs(self): -        def run(a, b): -            self.assertEqual(a, 4) -            self.assertEqual(b, 2) -            return 42 -        x = RawGreenlet(run).switch(a=4, b=2) -        self.assertEqual(x, 42) - -    def test_switch_kwargs_to_parent(self): -        def run(x): -            greenlet.getcurrent().parent.switch(x=x) -            greenlet.getcurrent().parent.switch(2, x=3) -            return x, x ** 2 -        g = RawGreenlet(run) -        self.assertEqual({'x': 3}, g.switch(3)) -        self.assertEqual(((2,), {'x': 3}), g.switch()) -        self.assertEqual((3, 9), g.switch()) - -    def test_switch_to_another_thread(self): -        data = {} -        created_event = threading.Event() -        done_event = threading.Event() - -        def run(): -            data['g'] = RawGreenlet(lambda: None) -            created_event.set() -            done_event.wait(10) -        thread = threading.Thread(target=run) -        thread.start() -        created_event.wait(10) -        with self.assertRaises(greenlet.error): -            data['g'].switch() -        done_event.set() -        thread.join(10) -        # XXX: Should handle this automatically -        data.clear() - -    def test_exc_state(self): -        def f(): -            try: -                raise ValueError('fun') -            except: # pylint:disable=bare-except -                exc_info = sys.exc_info() -                RawGreenlet(h).switch() -                self.assertEqual(exc_info, sys.exc_info()) - -        def h(): -            self.assertEqual(sys.exc_info(), (None, None, None)) - -        RawGreenlet(f).switch() - -    def test_instance_dict(self): -        def f(): -            greenlet.getcurrent().test = 42 -        def deldict(g): -            del g.__dict__ -        def setdict(g, value): -            g.__dict__ = value -        g = RawGreenlet(f) -        self.assertEqual(g.__dict__, {}) -        g.switch() -        self.assertEqual(g.test, 42) -        self.assertEqual(g.__dict__, {'test': 42}) -        g.__dict__ = g.__dict__ -        self.assertEqual(g.__dict__, {'test': 42}) -        self.assertRaises(TypeError, deldict, g) -        self.assertRaises(TypeError, setdict, g, 42) - -    def test_running_greenlet_has_no_run(self): -        has_run = [] -        def func(): -            has_run.append( -                hasattr(greenlet.getcurrent(), 'run') -            ) - -        g = RawGreenlet(func) -        g.switch() -        self.assertEqual(has_run, [False]) - -    def test_deepcopy(self): -        import copy -        self.assertRaises(TypeError, copy.copy, RawGreenlet()) -        self.assertRaises(TypeError, copy.deepcopy, RawGreenlet()) - -    def test_parent_restored_on_kill(self): -        hub = RawGreenlet(lambda: None) -        main = greenlet.getcurrent() -        result = [] -        def worker(): -            try: -                # Wait to be killed by going back to the test. -                main.switch() -            except greenlet.GreenletExit: -                # Resurrect and switch to parent -                result.append(greenlet.getcurrent().parent) -                result.append(greenlet.getcurrent()) -                hub.switch() -        g = RawGreenlet(worker, parent=hub) -        g.switch() -        # delete the only reference, thereby raising GreenletExit -        del g -        self.assertTrue(result) -        self.assertIs(result[0], main) -        self.assertIs(result[1].parent, hub) -        # Delete them, thereby breaking the cycle between the greenlet -        # and the frame, which otherwise would never be collectable -        # XXX: We should be able to automatically fix this. -        del result[:] -        hub = None -        main = None - -    def test_parent_return_failure(self): -        # No run causes AttributeError on switch -        g1 = RawGreenlet() -        # Greenlet that implicitly switches to parent -        g2 = RawGreenlet(lambda: None, parent=g1) -        # AttributeError should propagate to us, no fatal errors -        with self.assertRaises(AttributeError): -            g2.switch() - -    def test_throw_exception_not_lost(self): -        class mygreenlet(RawGreenlet): -            def __getattribute__(self, name): -                try: -                    raise Exception # pylint:disable=broad-exception-raised -                except: # pylint:disable=bare-except -                    pass -                return RawGreenlet.__getattribute__(self, name) -        g = mygreenlet(lambda: None) -        self.assertRaises(SomeError, g.throw, SomeError()) - -    @fails_leakcheck -    def _do_test_throw_to_dead_thread_doesnt_crash(self, wait_for_cleanup=False): -        result = [] -        def worker(): -            greenlet.getcurrent().parent.switch() - -        def creator(): -            g = RawGreenlet(worker) -            g.switch() -            result.append(g) -            if wait_for_cleanup: -                # Let this greenlet eventually be cleaned up. -                g.switch() -                greenlet.getcurrent() -        t = threading.Thread(target=creator) -        t.start() -        t.join(10) -        del t -        # But, depending on the operating system, the thread -        # deallocator may not actually have run yet! So we can't be -        # sure about the error message unless we wait. -        if wait_for_cleanup: -            self.wait_for_pending_cleanups() -        with self.assertRaises(greenlet.error) as exc: -            result[0].throw(SomeError) - -        if not wait_for_cleanup: -            self.assertIn( -                str(exc.exception), [ -                    "cannot switch to a different thread (which happens to have exited)", -                    "cannot switch to a different thread" -                ] -            ) -        else: -            self.assertEqual( -                str(exc.exception), -                "cannot switch to a different thread (which happens to have exited)", -            ) - -        if hasattr(result[0].gr_frame, 'clear'): -            # The frame is actually executing (it thinks), we can't clear it. -            with self.assertRaises(RuntimeError): -                result[0].gr_frame.clear() -        # Unfortunately, this doesn't actually clear the references, they're in the -        # fast local array. -        if not wait_for_cleanup: -            result[0].gr_frame.f_locals.clear() -        else: -            self.assertIsNone(result[0].gr_frame) - -        del creator -        worker = None -        del result[:] -        # XXX: we ought to be able to automatically fix this. -        # See issue 252 -        self.expect_greenlet_leak = True # direct us not to wait for it to go away - -    @fails_leakcheck -    def test_throw_to_dead_thread_doesnt_crash(self): -        self._do_test_throw_to_dead_thread_doesnt_crash() - -    def test_throw_to_dead_thread_doesnt_crash_wait(self): -        self._do_test_throw_to_dead_thread_doesnt_crash(True) - -    @fails_leakcheck -    def test_recursive_startup(self): -        class convoluted(RawGreenlet): -            def __init__(self): -                RawGreenlet.__init__(self) -                self.count = 0 -            def __getattribute__(self, name): -                if name == 'run' and self.count == 0: -                    self.count = 1 -                    self.switch(43) -                return RawGreenlet.__getattribute__(self, name) -            def run(self, value): -                while True: -                    self.parent.switch(value) -        g = convoluted() -        self.assertEqual(g.switch(42), 43) -        # Exits the running greenlet, otherwise it leaks -        # XXX: We should be able to automatically fix this -        #g.throw(greenlet.GreenletExit) -        #del g -        self.expect_greenlet_leak = True - -    def test_threaded_updatecurrent(self): -        # released when main thread should execute -        lock1 = threading.Lock() -        lock1.acquire() -        # released when another thread should execute -        lock2 = threading.Lock() -        lock2.acquire() -        class finalized(object): -            def __del__(self): -                # happens while in green_updatecurrent() in main greenlet -                # should be very careful not to accidentally call it again -                # at the same time we must make sure another thread executes -                lock2.release() -                lock1.acquire() -                # now ts_current belongs to another thread -        def deallocator(): -            greenlet.getcurrent().parent.switch() -        def fthread(): -            lock2.acquire() -            greenlet.getcurrent() -            del g[0] -            lock1.release() -            lock2.acquire() -            greenlet.getcurrent() -            lock1.release() -        main = greenlet.getcurrent() -        g = [RawGreenlet(deallocator)] -        g[0].bomb = finalized() -        g[0].switch() -        t = threading.Thread(target=fthread) -        t.start() -        # let another thread grab ts_current and deallocate g[0] -        lock2.release() -        lock1.acquire() -        # this is the corner stone -        # getcurrent() will notice that ts_current belongs to another thread -        # and start the update process, which would notice that g[0] should -        # be deallocated, and that will execute an object's finalizer. Now, -        # that object will let another thread run so it can grab ts_current -        # again, which would likely crash the interpreter if there's no -        # check for this case at the end of green_updatecurrent(). This test -        # passes if getcurrent() returns correct result, but it's likely -        # to randomly crash if it's not anyway. -        self.assertEqual(greenlet.getcurrent(), main) -        # wait for another thread to complete, just in case -        t.join(10) - -    def test_dealloc_switch_args_not_lost(self): -        seen = [] -        def worker(): -            # wait for the value -            value = greenlet.getcurrent().parent.switch() -            # delete all references to ourself -            del worker[0] -            initiator.parent = greenlet.getcurrent().parent -            # switch to main with the value, but because -            # ts_current is the last reference to us we -            # return here immediately, where we resurrect ourself. -            try: -                greenlet.getcurrent().parent.switch(value) -            finally: -                seen.append(greenlet.getcurrent()) -        def initiator(): -            return 42 # implicitly falls thru to parent - -        worker = [RawGreenlet(worker)] - -        worker[0].switch() # prime worker -        initiator = RawGreenlet(initiator, worker[0]) -        value = initiator.switch() -        self.assertTrue(seen) -        self.assertEqual(value, 42) - -    def test_tuple_subclass(self): -        # The point of this test is to see what happens when a custom -        # tuple subclass is used as an object passed directly to the C -        # function ``green_switch``; part of ``green_switch`` checks -        # the ``len()`` of the ``args`` tuple, and that can call back -        # into Python. Here, when it calls back into Python, we -        # recursively enter ``green_switch`` again. - -        # This test is really only relevant on Python 2. The builtin -        # `apply` function directly passes the given args tuple object -        # to the underlying function, whereas the Python 3 version -        # unpacks and repacks into an actual tuple. This could still -        # happen using the C API on Python 3 though. We should write a -        # builtin version of apply() ourself. -        def _apply(func, a, k): -            func(*a, **k) - -        class mytuple(tuple): -            def __len__(self): -                greenlet.getcurrent().switch() -                return tuple.__len__(self) -        args = mytuple() -        kwargs = dict(a=42) -        def switchapply(): -            _apply(greenlet.getcurrent().parent.switch, args, kwargs) -        g = RawGreenlet(switchapply) -        self.assertEqual(g.switch(), kwargs) - -    def test_abstract_subclasses(self): -        AbstractSubclass = ABCMeta( -            'AbstractSubclass', -            (RawGreenlet,), -            {'run': abstractmethod(lambda self: None)}) - -        class BadSubclass(AbstractSubclass): -            pass - -        class GoodSubclass(AbstractSubclass): -            def run(self): -                pass - -        GoodSubclass() # should not raise -        self.assertRaises(TypeError, BadSubclass) - -    def test_implicit_parent_with_threads(self): -        if not gc.isenabled(): -            return # cannot test with disabled gc -        N = gc.get_threshold()[0] -        if N < 50: -            return # cannot test with such a small N -        def attempt(): -            lock1 = threading.Lock() -            lock1.acquire() -            lock2 = threading.Lock() -            lock2.acquire() -            recycled = [False] -            def another_thread(): -                lock1.acquire() # wait for gc -                greenlet.getcurrent() # update ts_current -                lock2.release() # release gc -            t = threading.Thread(target=another_thread) -            t.start() -            class gc_callback(object): -                def __del__(self): -                    lock1.release() -                    lock2.acquire() -                    recycled[0] = True -            class garbage(object): -                def __init__(self): -                    self.cycle = self -                    self.callback = gc_callback() -            l = [] -            x = range(N*2) -            current = greenlet.getcurrent() -            g = garbage() -            for _ in x: -                g = None # lose reference to garbage -                if recycled[0]: -                    # gc callback called prematurely -                    t.join(10) -                    return False -                last = RawGreenlet() -                if recycled[0]: -                    break # yes! gc called in green_new -                l.append(last) # increase allocation counter -            else: -                # gc callback not called when expected -                gc.collect() -                if recycled[0]: -                    t.join(10) -                return False -            self.assertEqual(last.parent, current) -            for g in l: -                self.assertEqual(g.parent, current) -            return True -        for _ in range(5): -            if attempt(): -                break - -    def test_issue_245_reference_counting_subclass_no_threads(self): -        # https://github.com/python-greenlet/greenlet/issues/245 -        # Before the fix, this crashed pretty reliably on -        # Python 3.10, at least on macOS; but much less reliably on other -        # interpreters (memory layout must have changed). -        # The threaded test crashed more reliably on more interpreters. -        from greenlet import getcurrent -        from greenlet import GreenletExit - -        class Greenlet(RawGreenlet): -            pass - -        initial_refs = sys.getrefcount(Greenlet) -        # This has to be an instance variable because -        # Python 2 raises a SyntaxError if we delete a local -        # variable referenced in an inner scope. -        self.glets = [] # pylint:disable=attribute-defined-outside-init - -        def greenlet_main(): -            try: -                getcurrent().parent.switch() -            except GreenletExit: -                self.glets.append(getcurrent()) - -        # Before the -        for _ in range(10): -            Greenlet(greenlet_main).switch() - -        del self.glets -        self.assertEqual(sys.getrefcount(Greenlet), initial_refs) - -    def test_issue_245_reference_counting_subclass_threads(self): -        # https://github.com/python-greenlet/greenlet/issues/245 -        from threading import Thread -        from threading import Event - -        from greenlet import getcurrent - -        class MyGreenlet(RawGreenlet): -            pass - -        glets = [] -        ref_cleared = Event() - -        def greenlet_main(): -            getcurrent().parent.switch() - -        def thread_main(greenlet_running_event): -            mine = MyGreenlet(greenlet_main) -            glets.append(mine) -            # The greenlets being deleted must be active -            mine.switch() -            # Don't keep any reference to it in this thread -            del mine -            # Let main know we published our greenlet. -            greenlet_running_event.set() -            # Wait for main to let us know the references are -            # gone and the greenlet objects no longer reachable -            ref_cleared.wait(10) -            # The creating thread must call getcurrent() (or a few other -            # greenlet APIs) because that's when the thread-local list of dead -            # greenlets gets cleared. -            getcurrent() - -        # We start with 3 references to the subclass: -        # - This module -        # - Its __mro__ -        # - The __subclassess__ attribute of greenlet -        # - (If we call gc.get_referents(), we find four entries, including -        #   some other tuple ``(greenlet)`` that I'm not sure about but must be part -        #   of the machinery.) -        # -        # On Python 3.10 it's often enough to just run 3 threads; on Python 2.7, -        # more threads are needed, and the results are still -        # non-deterministic. Presumably the memory layouts are different -        initial_refs = sys.getrefcount(MyGreenlet) -        thread_ready_events = [] -        for _ in range( -                initial_refs + 45 -        ): -            event = Event() -            thread = Thread(target=thread_main, args=(event,)) -            thread_ready_events.append(event) -            thread.start() - - -        for done_event in thread_ready_events: -            done_event.wait(10) - - -        del glets[:] -        ref_cleared.set() -        # Let any other thread run; it will crash the interpreter -        # if not fixed (or silently corrupt memory and we possibly crash -        # later). -        self.wait_for_pending_cleanups() -        self.assertEqual(sys.getrefcount(MyGreenlet), initial_refs) - -    def test_falling_off_end_switches_to_unstarted_parent_raises_error(self): -        def no_args(): -            return 13 - -        parent_never_started = RawGreenlet(no_args) - -        def leaf(): -            return 42 - -        child = RawGreenlet(leaf, parent_never_started) - -        # Because the run function takes to arguments -        with self.assertRaises(TypeError): -            child.switch() - -    def test_falling_off_end_switches_to_unstarted_parent_works(self): -        def one_arg(x): -            return (x, 24) - -        parent_never_started = RawGreenlet(one_arg) - -        def leaf(): -            return 42 - -        child = RawGreenlet(leaf, parent_never_started) - -        result = child.switch() -        self.assertEqual(result, (42, 24)) - -    def test_switch_to_dead_greenlet_with_unstarted_perverse_parent(self): -        class Parent(RawGreenlet): -            def __getattribute__(self, name): -                if name == 'run': -                    raise SomeError - - -        parent_never_started = Parent() -        seen = [] -        child = RawGreenlet(lambda: seen.append(42), parent_never_started) -        # Because we automatically start the parent when the child is -        # finished -        with self.assertRaises(SomeError): -            child.switch() - -        self.assertEqual(seen, [42]) - -        with self.assertRaises(SomeError): -            child.switch() -        self.assertEqual(seen, [42]) - -    def test_switch_to_dead_greenlet_reparent(self): -        seen = [] -        parent_never_started = RawGreenlet(lambda: seen.append(24)) -        child = RawGreenlet(lambda: seen.append(42)) - -        child.switch() -        self.assertEqual(seen, [42]) - -        child.parent = parent_never_started -        # This actually is the same as switching to the parent. -        result = child.switch() -        self.assertIsNone(result) -        self.assertEqual(seen, [42, 24]) - -    def test_can_access_f_back_of_suspended_greenlet(self): -        # This tests our frame rewriting to work around Python 3.12+ having -        # some interpreter frames on the C stack. It will crash in the absence -        # of that logic. -        main = greenlet.getcurrent() - -        def outer(): -            inner() - -        def inner(): -            main.switch(sys._getframe(0)) - -        hub = RawGreenlet(outer) -        # start it -        hub.switch() - -        # start another greenlet to make sure we aren't relying on -        # anything in `hub` still being on the C stack -        unrelated = RawGreenlet(lambda: None) -        unrelated.switch() - -        # now it is suspended -        self.assertIsNotNone(hub.gr_frame) -        self.assertEqual(hub.gr_frame.f_code.co_name, "inner") -        self.assertIsNotNone(hub.gr_frame.f_back) -        self.assertEqual(hub.gr_frame.f_back.f_code.co_name, "outer") -        # The next line is what would crash -        self.assertIsNone(hub.gr_frame.f_back.f_back) - -    def test_get_stack_with_nested_c_calls(self): -        from functools import partial -        from . import _test_extension_cpp - -        def recurse(v): -            if v > 0: -                return v * _test_extension_cpp.test_call(partial(recurse, v - 1)) -            return greenlet.getcurrent().parent.switch() - -        gr = RawGreenlet(recurse) -        gr.switch(5) -        frame = gr.gr_frame -        for i in range(5): -            self.assertEqual(frame.f_locals["v"], i) -            frame = frame.f_back -        self.assertEqual(frame.f_locals["v"], 5) -        self.assertIsNone(frame.f_back) -        self.assertEqual(gr.switch(10), 1200)  # 1200 = 5! * 10 - -    def test_frames_always_exposed(self): -        # On Python 3.12 this will crash if we don't set the -        # gr_frames_always_exposed attribute. More background: -        # https://github.com/python-greenlet/greenlet/issues/388 -        main = greenlet.getcurrent() - -        def outer(): -            inner(sys._getframe(0)) - -        def inner(frame): -            main.switch(frame) - -        gr = RawGreenlet(outer) -        frame = gr.switch() - -        # Do something else to clobber the part of the C stack used by `gr`, -        # so we can't skate by on "it just happened to still be there" -        unrelated = RawGreenlet(lambda: None) -        unrelated.switch() - -        self.assertEqual(frame.f_code.co_name, "outer") -        # The next line crashes on 3.12 if we haven't exposed the frames. -        self.assertIsNone(frame.f_back) - - -class TestGreenletSetParentErrors(TestCase): -    def test_threaded_reparent(self): -        data = {} -        created_event = threading.Event() -        done_event = threading.Event() - -        def run(): -            data['g'] = RawGreenlet(lambda: None) -            created_event.set() -            done_event.wait(10) - -        def blank(): -            greenlet.getcurrent().parent.switch() - -        thread = threading.Thread(target=run) -        thread.start() -        created_event.wait(10) -        g = RawGreenlet(blank) -        g.switch() -        with self.assertRaises(ValueError) as exc: -            g.parent = data['g'] -        done_event.set() -        thread.join(10) - -        self.assertEqual(str(exc.exception), "parent cannot be on a different thread") - -    def test_unexpected_reparenting(self): -        another = [] -        def worker(): -            g = RawGreenlet(lambda: None) -            another.append(g) -            g.switch() -        t = threading.Thread(target=worker) -        t.start() -        t.join(10) -        # The first time we switch (running g_initialstub(), which is -        # when we look up the run attribute) we attempt to change the -        # parent to one from another thread (which also happens to be -        # dead). ``g_initialstub()`` should detect this and raise a -        # greenlet error. -        # -        # EXCEPT: With the fix for #252, this is actually detected -        # sooner, when setting the parent itself. Prior to that fix, -        # the main greenlet from the background thread kept a valid -        # value for ``run_info``, and appeared to be a valid parent -        # until we actually started the greenlet. But now that it's -        # cleared, this test is catching whether ``green_setparent`` -        # can detect the dead thread. -        # -        # Further refactoring once again changes this back to a greenlet.error -        # -        # We need to wait for the cleanup to happen, but we're -        # deliberately leaking a main greenlet here. -        self.wait_for_pending_cleanups(initial_main_greenlets=self.main_greenlets_before_test + 1) - -        class convoluted(RawGreenlet): -            def __getattribute__(self, name): -                if name == 'run': -                    self.parent = another[0] # pylint:disable=attribute-defined-outside-init -                return RawGreenlet.__getattribute__(self, name) -        g = convoluted(lambda: None) -        with self.assertRaises(greenlet.error) as exc: -            g.switch() -        self.assertEqual(str(exc.exception), -                         "cannot switch to a different thread (which happens to have exited)") -        del another[:] - -    def test_unexpected_reparenting_thread_running(self): -        # Like ``test_unexpected_reparenting``, except the background thread is -        # actually still alive. -        another = [] -        switched_to_greenlet = threading.Event() -        keep_main_alive = threading.Event() -        def worker(): -            g = RawGreenlet(lambda: None) -            another.append(g) -            g.switch() -            switched_to_greenlet.set() -            keep_main_alive.wait(10) -        class convoluted(RawGreenlet): -            def __getattribute__(self, name): -                if name == 'run': -                    self.parent = another[0] # pylint:disable=attribute-defined-outside-init -                return RawGreenlet.__getattribute__(self, name) - -        t = threading.Thread(target=worker) -        t.start() - -        switched_to_greenlet.wait(10) -        try: -            g = convoluted(lambda: None) - -            with self.assertRaises(greenlet.error) as exc: -                g.switch() -            self.assertEqual(str(exc.exception), "cannot switch to a different thread") -        finally: -            keep_main_alive.set() -            t.join(10) -            # XXX: Should handle this automatically. -            del another[:] - -    def test_cannot_delete_parent(self): -        worker = RawGreenlet(lambda: None) -        self.assertIs(worker.parent, greenlet.getcurrent()) - -        with self.assertRaises(AttributeError) as exc: -            del worker.parent -        self.assertEqual(str(exc.exception), "can't delete attribute") - -    def test_cannot_delete_parent_of_main(self): -        with self.assertRaises(AttributeError) as exc: -            del greenlet.getcurrent().parent -        self.assertEqual(str(exc.exception), "can't delete attribute") - - -    def test_main_greenlet_parent_is_none(self): -        # assuming we're in a main greenlet here. -        self.assertIsNone(greenlet.getcurrent().parent) - -    def test_set_parent_wrong_types(self): -        def bg(): -            # Go back to main. -            greenlet.getcurrent().parent.switch() - -        def check(glet): -            for p in None, 1, self, "42": -                with self.assertRaises(TypeError) as exc: -                    glet.parent = p - -                self.assertEqual( -                    str(exc.exception), -                    "GreenletChecker: Expected any type of greenlet, not " + type(p).__name__) - -        # First, not running -        g = RawGreenlet(bg) -        self.assertFalse(g) -        check(g) - -        # Then when running. -        g.switch() -        self.assertTrue(g) -        check(g) - -        # Let it finish -        g.switch() - - -    def test_trivial_cycle(self): -        glet = RawGreenlet(lambda: None) -        with self.assertRaises(ValueError) as exc: -            glet.parent = glet -        self.assertEqual(str(exc.exception), "cyclic parent chain") - -    def test_trivial_cycle_main(self): -        # This used to produce a ValueError, but we catch it earlier than that now. -        with self.assertRaises(AttributeError) as exc: -            greenlet.getcurrent().parent = greenlet.getcurrent() -        self.assertEqual(str(exc.exception), "cannot set the parent of a main greenlet") - -    def test_deeper_cycle(self): -        g1 = RawGreenlet(lambda: None) -        g2 = RawGreenlet(lambda: None) -        g3 = RawGreenlet(lambda: None) - -        g1.parent = g2 -        g2.parent = g3 -        with self.assertRaises(ValueError) as exc: -            g3.parent = g1 -        self.assertEqual(str(exc.exception), "cyclic parent chain") - - -class TestRepr(TestCase): - -    def assertEndsWith(self, got, suffix): -        self.assertTrue(got.endswith(suffix), (got, suffix)) - -    def test_main_while_running(self): -        r = repr(greenlet.getcurrent()) -        self.assertEndsWith(r, " current active started main>") - -    def test_main_in_background(self): -        main = greenlet.getcurrent() -        def run(): -            return repr(main) - -        g = RawGreenlet(run) -        r = g.switch() -        self.assertEndsWith(r, ' suspended active started main>') - -    def test_initial(self): -        r = repr(RawGreenlet()) -        self.assertEndsWith(r, ' pending>') - -    def test_main_from_other_thread(self): -        main = greenlet.getcurrent() - -        class T(threading.Thread): -            original_main = thread_main = None -            main_glet = None -            def run(self): -                self.original_main = repr(main) -                self.main_glet = greenlet.getcurrent() -                self.thread_main = repr(self.main_glet) - -        t = T() -        t.start() -        t.join(10) - -        self.assertEndsWith(t.original_main, ' suspended active started main>') -        self.assertEndsWith(t.thread_main, ' current active started main>') -        # give the machinery time to notice the death of the thread, -        # and clean it up. Note that we don't use -        # ``expect_greenlet_leak`` or wait_for_pending_cleanups, -        # because at this point we know we have an extra greenlet -        # still reachable. -        for _ in range(3): -            time.sleep(0.001) - -        # In the past, main greenlets, even from dead threads, never -        # really appear dead. We have fixed that, and we also report -        # that the thread is dead in the repr. (Do this multiple times -        # to make sure that we don't self-modify and forget our state -        # in the C++ code). -        for _ in range(3): -            self.assertTrue(t.main_glet.dead) -            r = repr(t.main_glet) -            self.assertEndsWith(r, ' (thread exited) dead>') - -    def test_dead(self): -        g = RawGreenlet(lambda: None) -        g.switch() -        self.assertEndsWith(repr(g), ' dead>') -        self.assertNotIn('suspended', repr(g)) -        self.assertNotIn('started', repr(g)) -        self.assertNotIn('active', repr(g)) - -    def test_formatting_produces_native_str(self): -        # https://github.com/python-greenlet/greenlet/issues/218 -        # %s formatting on Python 2 was producing unicode, not str. - -        g_dead = RawGreenlet(lambda: None) -        g_not_started = RawGreenlet(lambda: None) -        g_cur = greenlet.getcurrent() - -        for g in g_dead, g_not_started, g_cur: - -            self.assertIsInstance( -                '%s' % (g,), -                str -            ) -            self.assertIsInstance( -                '%r' % (g,), -                str, -            ) - - -class TestMainGreenlet(TestCase): -    # Tests some implementation details, and relies on some -    # implementation details. - -    def _check_current_is_main(self): -        # implementation detail -        assert 'main' in repr(greenlet.getcurrent()) - -        t = type(greenlet.getcurrent()) -        assert 'main' not in repr(t) -        return t - -    def test_main_greenlet_type_can_be_subclassed(self): -        main_type = self._check_current_is_main() -        subclass = type('subclass', (main_type,), {}) -        self.assertIsNotNone(subclass) - -    def test_main_greenlet_is_greenlet(self): -        self._check_current_is_main() -        self.assertIsInstance(greenlet.getcurrent(), RawGreenlet) - - - -class TestBrokenGreenlets(TestCase): -    # Tests for things that used to, or still do, terminate the interpreter. -    # This often means doing unsavory things. - -    def test_failed_to_initialstub(self): -        def func(): -            raise AssertionError("Never get here") - - -        g = greenlet._greenlet.UnswitchableGreenlet(func) -        g.force_switch_error = True - -        with self.assertRaisesRegex(SystemError, -                                    "Failed to switch stacks into a greenlet for the first time."): -            g.switch() - -    def test_failed_to_switch_into_running(self): -        runs = [] -        def func(): -            runs.append(1) -            greenlet.getcurrent().parent.switch() -            runs.append(2) -            greenlet.getcurrent().parent.switch() -            runs.append(3) # pragma: no cover - -        g = greenlet._greenlet.UnswitchableGreenlet(func) -        g.switch() -        self.assertEqual(runs, [1]) -        g.switch() -        self.assertEqual(runs, [1, 2]) -        g.force_switch_error = True - -        with self.assertRaisesRegex(SystemError, -                                    "Failed to switch stacks into a running greenlet."): -            g.switch() - -        # If we stopped here, we would fail the leakcheck, because we've left -        # the ``inner_bootstrap()`` C frame and its descendents hanging around, -        # which have a bunch of Python references. They'll never get cleaned up -        # if we don't let the greenlet finish. -        g.force_switch_error = False -        g.switch() -        self.assertEqual(runs, [1, 2, 3]) - -    def test_failed_to_slp_switch_into_running(self): -        ex = self.assertScriptRaises('fail_slp_switch.py') - -        self.assertIn('fail_slp_switch is running', ex.output) -        self.assertIn(ex.returncode, self.get_expected_returncodes_for_aborted_process()) - -    def test_reentrant_switch_two_greenlets(self): -        # Before we started capturing the arguments in g_switch_finish, this could crash. -        output = self.run_script('fail_switch_two_greenlets.py') -        self.assertIn('In g1_run', output) -        self.assertIn('TRACE', output) -        self.assertIn('LEAVE TRACE', output) -        self.assertIn('Falling off end of main', output) -        self.assertIn('Falling off end of g1_run', output) -        self.assertIn('Falling off end of g2', output) - -    def test_reentrant_switch_three_greenlets(self): -        # On debug builds of greenlet, this used to crash with an assertion error; -        # on non-debug versions, it ran fine (which it should not do!). -        # Now it always crashes correctly with a TypeError -        ex = self.assertScriptRaises('fail_switch_three_greenlets.py', exitcodes=(1,)) - -        self.assertIn('TypeError', ex.output) -        self.assertIn('positional arguments', ex.output) - -    def test_reentrant_switch_three_greenlets2(self): -        # This actually passed on debug and non-debug builds. It -        # should probably have been triggering some debug assertions -        # but it didn't. -        # -        # I think the fixes for the above test also kicked in here. -        output = self.run_script('fail_switch_three_greenlets2.py') -        self.assertIn( -            "RESULTS: [('trace', 'switch'), " -            "('trace', 'switch'), ('g2 arg', 'g2 from tracefunc'), " -            "('trace', 'switch'), ('main g1', 'from g2_run'), ('trace', 'switch'), " -            "('g1 arg', 'g1 from main'), ('trace', 'switch'), ('main g2', 'from g1_run'), " -            "('trace', 'switch'), ('g1 from parent', 'g1 from main 2'), ('trace', 'switch'), " -            "('main g1.2', 'g1 done'), ('trace', 'switch'), ('g2 from parent', ()), " -            "('trace', 'switch'), ('main g2.2', 'g2 done')]", -            output -        ) - -    def test_reentrant_switch_GreenletAlreadyStartedInPython(self): -        output = self.run_script('fail_initialstub_already_started.py') - -        self.assertIn( -            "RESULTS: ['Begin C', 'Switch to b from B.__getattribute__ in C', " -            "('Begin B', ()), '_B_run switching to main', ('main from c', 'From B'), " -            "'B.__getattribute__ back from main in C', ('Begin A', (None,)), " -            "('A dead?', True, 'B dead?', True, 'C dead?', False), " -            "'C done', ('main from c.2', None)]", -            output -        ) - -    def test_reentrant_switch_run_callable_has_del(self): -        output = self.run_script('fail_clearing_run_switches.py') -        self.assertIn( -             "RESULTS [" -            "('G.__getattribute__', 'run'), ('RunCallable', '__del__'), " -            "('main: g.switch()', 'from RunCallable'), ('run_func', 'enter')" -            "]", -            output -        ) - -if __name__ == '__main__': -    import unittest -    unittest.main() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_greenlet_trash.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_greenlet_trash.py deleted file mode 100644 index 8d9716e..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_greenlet_trash.py +++ /dev/null @@ -1,178 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tests for greenlets interacting with the CPython trash can API. - -The CPython trash can API is not designed to be re-entered from a -single thread. But this can happen using greenlets, if something -during the object deallocation process switches greenlets, and this second -greenlet then causes the trash can to get entered again. Here, we do this -very explicitly, but in other cases (like gevent) it could be arbitrarily more -complicated: for example, a weakref callback might try to acquire a lock that's -already held by another greenlet; that would allow a greenlet switch to occur. - -See https://github.com/gevent/gevent/issues/1909 - -This test is fragile and relies on details of the CPython -implementation (like most of the rest of this package): - -    - We enter the trashcan and deferred deallocation after -      ``_PyTrash_UNWIND_LEVEL`` calls. This constant, defined in -      CPython's object.c, is generally 50. That's basically how many objects are required to -      get us into the deferred deallocation situation. - -    - The test fails by hitting an ``assert()`` in object.c; if the -      build didn't enable assert, then we don't catch this. - -    - If the test fails in that way, the interpreter crashes. -""" -from __future__ import print_function, absolute_import, division - -import unittest - -class TestTrashCanReEnter(unittest.TestCase): - -    def test_it(self): -        # Try several times to trigger it, because it isn't 100% -        # reliable. -        for _ in range(10): -            self.check_it() - -    def check_it(self): # pylint:disable=too-many-statements -        import greenlet -        from greenlet._greenlet import get_tstate_trash_delete_nesting # pylint:disable=no-name-in-module - -        main = greenlet.getcurrent() - -        assert get_tstate_trash_delete_nesting() == 0 - -        # We expect to be in deferred deallocation after this many -        # deallocations have occurred. TODO: I wish we had a better way to do -        # this --- that was before get_tstate_trash_delete_nesting; perhaps -        # we can use that API to do better? -        TRASH_UNWIND_LEVEL = 50 -        # How many objects to put in a container; it's the container that -        # queues objects for deferred deallocation. -        OBJECTS_PER_CONTAINER = 500 - -        class Dealloc: # define the class here because we alter class variables each time we run. -            """ -            An object with a ``__del__`` method. When it starts getting deallocated -            from a deferred trash can run, it switches greenlets, allocates more objects -            which then also go in the trash can. If we don't save state appropriately, -            nesting gets out of order and we can crash the interpreter. -            """ - -            #: Has our deallocation actually run and switched greenlets? -            #: When it does, this will be set to the current greenlet. This should -            #: be happening in the main greenlet, so we check that down below. -            SPAWNED = False - -            #: Has the background greenlet run? -            BG_RAN = False - -            BG_GLET = None - -            #: How many of these things have ever been allocated. -            CREATED = 0 - -            #: How many of these things have ever been deallocated. -            DESTROYED = 0 - -            #: How many were destroyed not in the main greenlet. There should always -            #: be some. -            #: If the test is broken or things change in the trashcan implementation, -            #: this may not be correct. -            DESTROYED_BG = 0 - -            def __init__(self, sequence_number): -                """ -                :param sequence_number: The ordinal of this object during -                   one particular creation run. This is used to detect (guess, really) -                   when we have entered the trash can's deferred deallocation. -                """ -                self.i = sequence_number -                Dealloc.CREATED += 1 - -            def __del__(self): -                if self.i == TRASH_UNWIND_LEVEL and not self.SPAWNED: -                    Dealloc.SPAWNED = greenlet.getcurrent() -                    other = Dealloc.BG_GLET = greenlet.greenlet(background_greenlet) -                    x = other.switch() -                    assert x == 42 -                    # It's important that we don't switch back to the greenlet, -                    # we leave it hanging there in an incomplete state. But we don't let it -                    # get collected, either. If we complete it now, while we're still -                    # in the scope of the initial trash can, things work out and we -                    # don't see the problem. We need this greenlet to complete -                    # at some point in the future, after we've exited this trash can invocation. -                    del other -                elif self.i == 40 and greenlet.getcurrent() is not main: -                    Dealloc.BG_RAN = True -                    try: -                        main.switch(42) -                    except greenlet.GreenletExit as ex: -                        # We expect this; all references to us go away -                        # while we're still running, and we need to finish deleting -                        # ourself. -                        Dealloc.BG_RAN = type(ex) -                        del ex - -                # Record the fact that we're dead last of all. This ensures that -                # we actually get returned too. -                Dealloc.DESTROYED += 1 -                if greenlet.getcurrent() is not main: -                    Dealloc.DESTROYED_BG += 1 - - -        def background_greenlet(): -            # We direct through a second function, instead of -            # directly calling ``make_some()``, so that we have complete -            # control over when these objects are destroyed: we need them -            # to be destroyed in the context of the background greenlet -            t = make_some() -            del t # Triggere deletion. - -        def make_some(): -            t = () -            i = OBJECTS_PER_CONTAINER -            while i: -                # Nest the tuples; it's the recursion that gets us -                # into trash. -                t = (Dealloc(i), t) -                i -= 1 -            return t - - -        some = make_some() -        self.assertEqual(Dealloc.CREATED, OBJECTS_PER_CONTAINER) -        self.assertEqual(Dealloc.DESTROYED, 0) - -        # If we're going to crash, it should be on the following line. -        # We only crash if ``assert()`` is enabled, of course. -        del some - -        # For non-debug builds of CPython, we won't crash. The best we can do is check -        # the nesting level explicitly. -        self.assertEqual(0, get_tstate_trash_delete_nesting()) - -        # Discard this, raising GreenletExit into where it is waiting. -        Dealloc.BG_GLET = None -        # The same nesting level maintains. -        self.assertEqual(0, get_tstate_trash_delete_nesting()) - -        # We definitely cleaned some up in the background -        self.assertGreater(Dealloc.DESTROYED_BG, 0) - -        # Make sure all the cleanups happened. -        self.assertIs(Dealloc.SPAWNED, main) -        self.assertTrue(Dealloc.BG_RAN) -        self.assertEqual(Dealloc.BG_RAN, greenlet.GreenletExit) -        self.assertEqual(Dealloc.CREATED, Dealloc.DESTROYED ) -        self.assertEqual(Dealloc.CREATED, OBJECTS_PER_CONTAINER * 2) - -        import gc -        gc.collect() - - -if __name__ == '__main__': -    unittest.main() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_leaks.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_leaks.py deleted file mode 100644 index ed1fa71..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_leaks.py +++ /dev/null @@ -1,443 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Testing scenarios that may have leaked. -""" -from __future__ import print_function, absolute_import, division - -import sys -import gc - -import time -import weakref -import threading - - -import greenlet -from . import TestCase -from .leakcheck import fails_leakcheck -from .leakcheck import ignores_leakcheck -from .leakcheck import RUNNING_ON_MANYLINUX - -# pylint:disable=protected-access - -assert greenlet.GREENLET_USE_GC # Option to disable this was removed in 1.0 - -class HasFinalizerTracksInstances(object): -    EXTANT_INSTANCES = set() -    def __init__(self, msg): -        self.msg = sys.intern(msg) -        self.EXTANT_INSTANCES.add(id(self)) -    def __del__(self): -        self.EXTANT_INSTANCES.remove(id(self)) -    def __repr__(self): -        return "<HasFinalizerTracksInstances at 0x%x %r>" % ( -            id(self), self.msg -        ) -    @classmethod -    def reset(cls): -        cls.EXTANT_INSTANCES.clear() - - -class TestLeaks(TestCase): - -    def test_arg_refs(self): -        args = ('a', 'b', 'c') -        refcount_before = sys.getrefcount(args) -        # pylint:disable=unnecessary-lambda -        g = greenlet.greenlet( -            lambda *args: greenlet.getcurrent().parent.switch(*args)) -        for _ in range(100): -            g.switch(*args) -        self.assertEqual(sys.getrefcount(args), refcount_before) - -    def test_kwarg_refs(self): -        kwargs = {} -        # pylint:disable=unnecessary-lambda -        g = greenlet.greenlet( -            lambda **kwargs: greenlet.getcurrent().parent.switch(**kwargs)) -        for _ in range(100): -            g.switch(**kwargs) -        self.assertEqual(sys.getrefcount(kwargs), 2) - - -    @staticmethod -    def __recycle_threads(): -        # By introducing a thread that does sleep we allow other threads, -        # that have triggered their __block condition, but did not have a -        # chance to deallocate their thread state yet, to finally do so. -        # The way it works is by requiring a GIL switch (different thread), -        # which does a GIL release (sleep), which might do a GIL switch -        # to finished threads and allow them to clean up. -        def worker(): -            time.sleep(0.001) -        t = threading.Thread(target=worker) -        t.start() -        time.sleep(0.001) -        t.join(10) - -    def test_threaded_leak(self): -        gg = [] -        def worker(): -            # only main greenlet present -            gg.append(weakref.ref(greenlet.getcurrent())) -        for _ in range(2): -            t = threading.Thread(target=worker) -            t.start() -            t.join(10) -            del t -        greenlet.getcurrent() # update ts_current -        self.__recycle_threads() -        greenlet.getcurrent() # update ts_current -        gc.collect() -        greenlet.getcurrent() # update ts_current -        for g in gg: -            self.assertIsNone(g()) - -    def test_threaded_adv_leak(self): -        gg = [] -        def worker(): -            # main and additional *finished* greenlets -            ll = greenlet.getcurrent().ll = [] -            def additional(): -                ll.append(greenlet.getcurrent()) -            for _ in range(2): -                greenlet.greenlet(additional).switch() -            gg.append(weakref.ref(greenlet.getcurrent())) -        for _ in range(2): -            t = threading.Thread(target=worker) -            t.start() -            t.join(10) -            del t -        greenlet.getcurrent() # update ts_current -        self.__recycle_threads() -        greenlet.getcurrent() # update ts_current -        gc.collect() -        greenlet.getcurrent() # update ts_current -        for g in gg: -            self.assertIsNone(g()) - -    def assertClocksUsed(self): -        used = greenlet._greenlet.get_clocks_used_doing_optional_cleanup() -        self.assertGreaterEqual(used, 0) -        # we don't lose the value -        greenlet._greenlet.enable_optional_cleanup(True) -        used2 = greenlet._greenlet.get_clocks_used_doing_optional_cleanup() -        self.assertEqual(used, used2) -        self.assertGreater(greenlet._greenlet.CLOCKS_PER_SEC, 1) - -    def _check_issue251(self, -                        manually_collect_background=True, -                        explicit_reference_to_switch=False): -        # See https://github.com/python-greenlet/greenlet/issues/251 -        # Killing a greenlet (probably not the main one) -        # in one thread from another thread would -        # result in leaking a list (the ts_delkey list). -        # We no longer use lists to hold that stuff, though. - -        # For the test to be valid, even empty lists have to be tracked by the -        # GC - -        assert gc.is_tracked([]) -        HasFinalizerTracksInstances.reset() -        greenlet.getcurrent() -        greenlets_before = self.count_objects(greenlet.greenlet, exact_kind=False) - -        background_glet_running = threading.Event() -        background_glet_killed = threading.Event() -        background_greenlets = [] - -        # XXX: Switching this to a greenlet subclass that overrides -        # run results in all callers failing the leaktest; that -        # greenlet instance is leaked. There's a bound method for -        # run() living on the stack of the greenlet in g_initialstub, -        # and since we don't manually switch back to the background -        # greenlet to let it "fall off the end" and exit the -        # g_initialstub function, it never gets cleaned up. Making the -        # garbage collector aware of this bound method (making it an -        # attribute of the greenlet structure and traversing into it) -        # doesn't help, for some reason. -        def background_greenlet(): -            # Throw control back to the main greenlet. -            jd = HasFinalizerTracksInstances("DELETING STACK OBJECT") -            greenlet._greenlet.set_thread_local( -                'test_leaks_key', -                HasFinalizerTracksInstances("DELETING THREAD STATE")) -            # Explicitly keeping 'switch' in a local variable -            # breaks this test in all versions -            if explicit_reference_to_switch: -                s = greenlet.getcurrent().parent.switch -                s([jd]) -            else: -                greenlet.getcurrent().parent.switch([jd]) - -        bg_main_wrefs = [] - -        def background_thread(): -            glet = greenlet.greenlet(background_greenlet) -            bg_main_wrefs.append(weakref.ref(glet.parent)) - -            background_greenlets.append(glet) -            glet.switch() # Be sure it's active. -            # Control is ours again. -            del glet # Delete one reference from the thread it runs in. -            background_glet_running.set() -            background_glet_killed.wait(10) - -            # To trigger the background collection of the dead -            # greenlet, thus clearing out the contents of the list, we -            # need to run some APIs. See issue 252. -            if manually_collect_background: -                greenlet.getcurrent() - - -        t = threading.Thread(target=background_thread) -        t.start() -        background_glet_running.wait(10) -        greenlet.getcurrent() -        lists_before = self.count_objects(list, exact_kind=True) - -        assert len(background_greenlets) == 1 -        self.assertFalse(background_greenlets[0].dead) -        # Delete the last reference to the background greenlet -        # from a different thread. This puts it in the background thread's -        # ts_delkey list. -        del background_greenlets[:] -        background_glet_killed.set() - -        # Now wait for the background thread to die. -        t.join(10) -        del t -        # As part of the fix for 252, we need to cycle the ceval.c -        # interpreter loop to be sure it has had a chance to process -        # the pending call. -        self.wait_for_pending_cleanups() - -        lists_after = self.count_objects(list, exact_kind=True) -        greenlets_after = self.count_objects(greenlet.greenlet, exact_kind=False) - -        # On 2.7, we observe that lists_after is smaller than -        # lists_before. No idea what lists got cleaned up. All the -        # Python 3 versions match exactly. -        self.assertLessEqual(lists_after, lists_before) -        # On versions after 3.6, we've successfully cleaned up the -        # greenlet references thanks to the internal "vectorcall" -        # protocol; prior to that, there is a reference path through -        # the ``greenlet.switch`` method still on the stack that we -        # can't reach to clean up. The C code goes through terrific -        # lengths to clean that up. -        if not explicit_reference_to_switch \ -           and greenlet._greenlet.get_clocks_used_doing_optional_cleanup() is not None: -            # If cleanup was disabled, though, we may not find it. -            self.assertEqual(greenlets_after, greenlets_before) -            if manually_collect_background: -                # TODO: Figure out how to make this work! -                # The one on the stack is still leaking somehow -                # in the non-manually-collect state. -                self.assertEqual(HasFinalizerTracksInstances.EXTANT_INSTANCES, set()) -        else: -            # The explicit reference prevents us from collecting it -            # and it isn't always found by the GC either for some -            # reason. The entire frame is leaked somehow, on some -            # platforms (e.g., MacPorts builds of Python (all -            # versions!)), but not on other platforms (the linux and -            # windows builds on GitHub actions and Appveyor). So we'd -            # like to write a test that proves that the main greenlet -            # sticks around, and we can on my machine (macOS 11.6, -            # MacPorts builds of everything) but we can't write that -            # same test on other platforms. However, hopefully iteration -            # done by leakcheck will find it. -            pass - -        if greenlet._greenlet.get_clocks_used_doing_optional_cleanup() is not None: -            self.assertClocksUsed() - -    def test_issue251_killing_cross_thread_leaks_list(self): -        self._check_issue251() - -    def test_issue251_with_cleanup_disabled(self): -        greenlet._greenlet.enable_optional_cleanup(False) -        try: -            self._check_issue251() -        finally: -            greenlet._greenlet.enable_optional_cleanup(True) - -    @fails_leakcheck -    def test_issue251_issue252_need_to_collect_in_background(self): -        # Between greenlet 1.1.2 and the next version, this was still -        # failing because the leak of the list still exists when we -        # don't call a greenlet API before exiting the thread. The -        # proximate cause is that neither of the two greenlets from -        # the background thread are actually being destroyed, even -        # though the GC is in fact visiting both objects. It's not -        # clear where that leak is? For some reason the thread-local -        # dict holding it isn't being cleaned up. -        # -        # The leak, I think, is in the CPYthon internal function that -        # calls into green_switch(). The argument tuple is still on -        # the C stack somewhere and can't be reached? That doesn't -        # make sense, because the tuple should be collectable when -        # this object goes away. -        # -        # Note that this test sometimes spuriously passes on Linux, -        # for some reason, but I've never seen it pass on macOS. -        self._check_issue251(manually_collect_background=False) - -    @fails_leakcheck -    def test_issue251_issue252_need_to_collect_in_background_cleanup_disabled(self): -        self.expect_greenlet_leak = True -        greenlet._greenlet.enable_optional_cleanup(False) -        try: -            self._check_issue251(manually_collect_background=False) -        finally: -            greenlet._greenlet.enable_optional_cleanup(True) - -    @fails_leakcheck -    def test_issue251_issue252_explicit_reference_not_collectable(self): -        self._check_issue251( -            manually_collect_background=False, -            explicit_reference_to_switch=True) - -    UNTRACK_ATTEMPTS = 100 - -    def _only_test_some_versions(self): -        # We're only looking for this problem specifically on 3.11, -        # and this set of tests is relatively fragile, depending on -        # OS and memory management details. So we want to run it on 3.11+ -        # (obviously) but not every older 3.x version in order to reduce -        # false negatives. At the moment, those false results seem to have -        # resolved, so we are actually running this on 3.8+ -        assert sys.version_info[0] >= 3 -        if sys.version_info[:2] < (3, 8): -            self.skipTest('Only observed on 3.11') -        if RUNNING_ON_MANYLINUX: -            self.skipTest("Slow and not worth repeating here") - -    @ignores_leakcheck -    # Because we're just trying to track raw memory, not objects, and running -    # the leakcheck makes an already slow test slower. -    def test_untracked_memory_doesnt_increase(self): -        # See https://github.com/gevent/gevent/issues/1924 -        # and https://github.com/python-greenlet/greenlet/issues/328 -        self._only_test_some_versions() -        def f(): -            return 1 - -        ITER = 10000 -        def run_it(): -            for _ in range(ITER): -                greenlet.greenlet(f).switch() - -        # Establish baseline -        for _ in range(3): -            run_it() - -        # uss: (Linux, macOS, Windows): aka "Unique Set Size", this is -        # the memory which is unique to a process and which would be -        # freed if the process was terminated right now. -        uss_before = self.get_process_uss() - -        for count in range(self.UNTRACK_ATTEMPTS): -            uss_before = max(uss_before, self.get_process_uss()) -            run_it() - -            uss_after = self.get_process_uss() -            if uss_after <= uss_before and count > 1: -                break - -        self.assertLessEqual(uss_after, uss_before) - -    def _check_untracked_memory_thread(self, deallocate_in_thread=True): -        self._only_test_some_versions() -        # Like the above test, but what if there are a bunch of -        # unfinished greenlets in a thread that dies? -        # Does it matter if we deallocate in the thread or not? -        EXIT_COUNT = [0] - -        def f(): -            try: -                greenlet.getcurrent().parent.switch() -            except greenlet.GreenletExit: -                EXIT_COUNT[0] += 1 -                raise -            return 1 - -        ITER = 10000 -        def run_it(): -            glets = [] -            for _ in range(ITER): -                # Greenlet starts, switches back to us. -                # We keep a strong reference to the greenlet though so it doesn't -                # get a GreenletExit exception. -                g = greenlet.greenlet(f) -                glets.append(g) -                g.switch() - -            return glets - -        test = self - -        class ThreadFunc: -            uss_before = uss_after = 0 -            glets = () -            ITER = 2 -            def __call__(self): -                self.uss_before = test.get_process_uss() - -                for _ in range(self.ITER): -                    self.glets += tuple(run_it()) - -                for g in self.glets: -                    test.assertIn('suspended active', str(g)) -                # Drop them. -                if deallocate_in_thread: -                    self.glets = () -                self.uss_after = test.get_process_uss() - -        # Establish baseline -        uss_before = uss_after = None -        for count in range(self.UNTRACK_ATTEMPTS): -            EXIT_COUNT[0] = 0 -            thread_func = ThreadFunc() -            t = threading.Thread(target=thread_func) -            t.start() -            t.join(30) -            self.assertFalse(t.is_alive()) - -            if uss_before is None: -                uss_before = thread_func.uss_before - -            uss_before = max(uss_before, thread_func.uss_before) -            if deallocate_in_thread: -                self.assertEqual(thread_func.glets, ()) -                self.assertEqual(EXIT_COUNT[0], ITER * thread_func.ITER) - -            del thread_func # Deallocate the greenlets; but this won't raise into them -            del t -            if not deallocate_in_thread: -                self.assertEqual(EXIT_COUNT[0], 0) -            if deallocate_in_thread: -                self.wait_for_pending_cleanups() - -            uss_after = self.get_process_uss() -            # See if we achieve a non-growth state at some point. Break when we do. -            if uss_after <= uss_before and count > 1: -                break - -        self.wait_for_pending_cleanups() -        uss_after = self.get_process_uss() -        self.assertLessEqual(uss_after, uss_before, "after attempts %d" % (count,)) - -    @ignores_leakcheck -    # Because we're just trying to track raw memory, not objects, and running -    # the leakcheck makes an already slow test slower. -    def test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_thread(self): -        self._check_untracked_memory_thread(deallocate_in_thread=True) - -    @ignores_leakcheck -    # Because the main greenlets from the background threads do not exit in a timely fashion, -    # we fail the object-based leakchecks. -    def test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_main(self): -        self._check_untracked_memory_thread(deallocate_in_thread=False) - -if __name__ == '__main__': -    __import__('unittest').main() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_stack_saved.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_stack_saved.py deleted file mode 100644 index b362bf9..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_stack_saved.py +++ /dev/null @@ -1,19 +0,0 @@ -import greenlet -from . import TestCase - - -class Test(TestCase): - -    def test_stack_saved(self): -        main = greenlet.getcurrent() -        self.assertEqual(main._stack_saved, 0) - -        def func(): -            main.switch(main._stack_saved) - -        g = greenlet.greenlet(func) -        x = g.switch() -        self.assertGreater(x, 0) -        self.assertGreater(g._stack_saved, 0) -        g.switch() -        self.assertEqual(g._stack_saved, 0) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_throw.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_throw.py deleted file mode 100644 index f4f9a14..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_throw.py +++ /dev/null @@ -1,128 +0,0 @@ -import sys - - -from greenlet import greenlet -from . import TestCase - -def switch(*args): -    return greenlet.getcurrent().parent.switch(*args) - - -class ThrowTests(TestCase): -    def test_class(self): -        def f(): -            try: -                switch("ok") -            except RuntimeError: -                switch("ok") -                return -            switch("fail") -        g = greenlet(f) -        res = g.switch() -        self.assertEqual(res, "ok") -        res = g.throw(RuntimeError) -        self.assertEqual(res, "ok") - -    def test_val(self): -        def f(): -            try: -                switch("ok") -            except RuntimeError: -                val = sys.exc_info()[1] -                if str(val) == "ciao": -                    switch("ok") -                    return -            switch("fail") - -        g = greenlet(f) -        res = g.switch() -        self.assertEqual(res, "ok") -        res = g.throw(RuntimeError("ciao")) -        self.assertEqual(res, "ok") - -        g = greenlet(f) -        res = g.switch() -        self.assertEqual(res, "ok") -        res = g.throw(RuntimeError, "ciao") -        self.assertEqual(res, "ok") - -    def test_kill(self): -        def f(): -            switch("ok") -            switch("fail") -        g = greenlet(f) -        res = g.switch() -        self.assertEqual(res, "ok") -        res = g.throw() -        self.assertTrue(isinstance(res, greenlet.GreenletExit)) -        self.assertTrue(g.dead) -        res = g.throw()    # immediately eaten by the already-dead greenlet -        self.assertTrue(isinstance(res, greenlet.GreenletExit)) - -    def test_throw_goes_to_original_parent(self): -        main = greenlet.getcurrent() - -        def f1(): -            try: -                main.switch("f1 ready to catch") -            except IndexError: -                return "caught" -            return "normal exit" - -        def f2(): -            main.switch("from f2") - -        g1 = greenlet(f1) -        g2 = greenlet(f2, parent=g1) -        with self.assertRaises(IndexError): -            g2.throw(IndexError) -        self.assertTrue(g2.dead) -        self.assertTrue(g1.dead) - -        g1 = greenlet(f1) -        g2 = greenlet(f2, parent=g1) -        res = g1.switch() -        self.assertEqual(res, "f1 ready to catch") -        res = g2.throw(IndexError) -        self.assertEqual(res, "caught") -        self.assertTrue(g2.dead) -        self.assertTrue(g1.dead) - -        g1 = greenlet(f1) -        g2 = greenlet(f2, parent=g1) -        res = g1.switch() -        self.assertEqual(res, "f1 ready to catch") -        res = g2.switch() -        self.assertEqual(res, "from f2") -        res = g2.throw(IndexError) -        self.assertEqual(res, "caught") -        self.assertTrue(g2.dead) -        self.assertTrue(g1.dead) - -    def test_non_traceback_param(self): -        with self.assertRaises(TypeError) as exc: -            greenlet.getcurrent().throw( -                Exception, -                Exception(), -                self -            ) -        self.assertEqual(str(exc.exception), -                         "throw() third argument must be a traceback object") - -    def test_instance_of_wrong_type(self): -        with self.assertRaises(TypeError) as exc: -            greenlet.getcurrent().throw( -                Exception(), -                BaseException() -            ) - -        self.assertEqual(str(exc.exception), -                         "instance exception may not have a separate value") - -    def test_not_throwable(self): -        with self.assertRaises(TypeError) as exc: -            greenlet.getcurrent().throw( -                "abc" -            ) -        self.assertEqual(str(exc.exception), -                         "exceptions must be classes, or instances, not str") diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_tracing.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_tracing.py deleted file mode 100644 index c044d4b..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_tracing.py +++ /dev/null @@ -1,291 +0,0 @@ -from __future__ import print_function -import sys -import greenlet -import unittest - -from . import TestCase -from . import PY312 - -# https://discuss.python.org/t/cpython-3-12-greenlet-and-tracing-profiling-how-to-not-crash-and-get-correct-results/33144/2 -DEBUG_BUILD_PY312 = ( -    PY312 and hasattr(sys, 'gettotalrefcount'), -    "Broken on debug builds of Python 3.12" -) - -class SomeError(Exception): -    pass - -class GreenletTracer(object): -    oldtrace = None - -    def __init__(self, error_on_trace=False): -        self.actions = [] -        self.error_on_trace = error_on_trace - -    def __call__(self, *args): -        self.actions.append(args) -        if self.error_on_trace: -            raise SomeError - -    def __enter__(self): -        self.oldtrace = greenlet.settrace(self) -        return self.actions - -    def __exit__(self, *args): -        greenlet.settrace(self.oldtrace) - - -class TestGreenletTracing(TestCase): -    """ -    Tests of ``greenlet.settrace()`` -    """ - -    def test_a_greenlet_tracing(self): -        main = greenlet.getcurrent() -        def dummy(): -            pass -        def dummyexc(): -            raise SomeError() - -        with GreenletTracer() as actions: -            g1 = greenlet.greenlet(dummy) -            g1.switch() -            g2 = greenlet.greenlet(dummyexc) -            self.assertRaises(SomeError, g2.switch) - -        self.assertEqual(actions, [ -            ('switch', (main, g1)), -            ('switch', (g1, main)), -            ('switch', (main, g2)), -            ('throw', (g2, main)), -        ]) - -    def test_b_exception_disables_tracing(self): -        main = greenlet.getcurrent() -        def dummy(): -            main.switch() -        g = greenlet.greenlet(dummy) -        g.switch() -        with GreenletTracer(error_on_trace=True) as actions: -            self.assertRaises(SomeError, g.switch) -            self.assertEqual(greenlet.gettrace(), None) - -        self.assertEqual(actions, [ -            ('switch', (main, g)), -        ]) - -    def test_set_same_tracer_twice(self): -        # https://github.com/python-greenlet/greenlet/issues/332 -        # Our logic in asserting that the tracefunction should -        # gain a reference was incorrect if the same tracefunction was set -        # twice. -        tracer = GreenletTracer() -        with tracer: -            greenlet.settrace(tracer) - - -class PythonTracer(object): -    oldtrace = None - -    def __init__(self): -        self.actions = [] - -    def __call__(self, frame, event, arg): -        # Record the co_name so we have an idea what function we're in. -        self.actions.append((event, frame.f_code.co_name)) - -    def __enter__(self): -        self.oldtrace = sys.setprofile(self) -        return self.actions - -    def __exit__(self, *args): -        sys.setprofile(self.oldtrace) - -def tpt_callback(): -    return 42 - -class TestPythonTracing(TestCase): -    """ -    Tests of the interaction of ``sys.settrace()`` -    with greenlet facilities. - -    NOTE: Most of this is probably CPython specific. -    """ - -    maxDiff = None - -    def test_trace_events_trivial(self): -        with PythonTracer() as actions: -            tpt_callback() -        # If we use the sys.settrace instead of setprofile, we get -        # this: - -        # self.assertEqual(actions, [ -        #     ('call', 'tpt_callback'), -        #     ('call', '__exit__'), -        # ]) - -        self.assertEqual(actions, [ -            ('return', '__enter__'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('call', '__exit__'), -            ('c_call', '__exit__'), -        ]) - -    def _trace_switch(self, glet): -        with PythonTracer() as actions: -            glet.switch() -        return actions - -    def _check_trace_events_func_already_set(self, glet): -        actions = self._trace_switch(glet) -        self.assertEqual(actions, [ -            ('return', '__enter__'), -            ('c_call', '_trace_switch'), -            ('call', 'run'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('return', 'run'), -            ('c_return', '_trace_switch'), -            ('call', '__exit__'), -            ('c_call', '__exit__'), -        ]) - -    def test_trace_events_into_greenlet_func_already_set(self): -        def run(): -            return tpt_callback() - -        self._check_trace_events_func_already_set(greenlet.greenlet(run)) - -    def test_trace_events_into_greenlet_subclass_already_set(self): -        class X(greenlet.greenlet): -            def run(self): -                return tpt_callback() -        self._check_trace_events_func_already_set(X()) - -    def _check_trace_events_from_greenlet_sets_profiler(self, g, tracer): -        g.switch() -        tpt_callback() -        tracer.__exit__() -        self.assertEqual(tracer.actions, [ -            ('return', '__enter__'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('return', 'run'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('call', '__exit__'), -            ('c_call', '__exit__'), -        ]) - - -    def test_trace_events_from_greenlet_func_sets_profiler(self): -        tracer = PythonTracer() -        def run(): -            tracer.__enter__() -            return tpt_callback() - -        self._check_trace_events_from_greenlet_sets_profiler(greenlet.greenlet(run), -                                                             tracer) - -    def test_trace_events_from_greenlet_subclass_sets_profiler(self): -        tracer = PythonTracer() -        class X(greenlet.greenlet): -            def run(self): -                tracer.__enter__() -                return tpt_callback() - -        self._check_trace_events_from_greenlet_sets_profiler(X(), tracer) - -    @unittest.skipIf(*DEBUG_BUILD_PY312) -    def test_trace_events_multiple_greenlets_switching(self): -        tracer = PythonTracer() - -        g1 = None -        g2 = None - -        def g1_run(): -            tracer.__enter__() -            tpt_callback() -            g2.switch() -            tpt_callback() -            return 42 - -        def g2_run(): -            tpt_callback() -            tracer.__exit__() -            tpt_callback() -            g1.switch() - -        g1 = greenlet.greenlet(g1_run) -        g2 = greenlet.greenlet(g2_run) - -        x = g1.switch() -        self.assertEqual(x, 42) -        tpt_callback() # ensure not in the trace -        self.assertEqual(tracer.actions, [ -            ('return', '__enter__'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('c_call', 'g1_run'), -            ('call', 'g2_run'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('call', '__exit__'), -            ('c_call', '__exit__'), -        ]) - -    @unittest.skipIf(*DEBUG_BUILD_PY312) -    def test_trace_events_multiple_greenlets_switching_siblings(self): -        # Like the first version, but get both greenlets running first -        # as "siblings" and then establish the tracing. -        tracer = PythonTracer() - -        g1 = None -        g2 = None - -        def g1_run(): -            greenlet.getcurrent().parent.switch() -            tracer.__enter__() -            tpt_callback() -            g2.switch() -            tpt_callback() -            return 42 - -        def g2_run(): -            greenlet.getcurrent().parent.switch() - -            tpt_callback() -            tracer.__exit__() -            tpt_callback() -            g1.switch() - -        g1 = greenlet.greenlet(g1_run) -        g2 = greenlet.greenlet(g2_run) - -        # Start g1 -        g1.switch() -        # And it immediately returns control to us. -        # Start g2 -        g2.switch() -        # Which also returns. Now kick of the real part of the -        # test. -        x = g1.switch() -        self.assertEqual(x, 42) - -        tpt_callback() # ensure not in the trace -        self.assertEqual(tracer.actions, [ -            ('return', '__enter__'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('c_call', 'g1_run'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('call', '__exit__'), -            ('c_call', '__exit__'), -        ]) - - -if __name__ == '__main__': -    unittest.main() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_version.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_version.py deleted file mode 100644 index 96c17cf..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_version.py +++ /dev/null @@ -1,41 +0,0 @@ -#! /usr/bin/env python -from __future__ import absolute_import -from __future__ import print_function - -import sys -import os -from unittest import TestCase as NonLeakingTestCase - -import greenlet - -# No reason to run this multiple times under leakchecks, -# it doesn't do anything. -class VersionTests(NonLeakingTestCase): -    def test_version(self): -        def find_dominating_file(name): -            if os.path.exists(name): -                return name - -            tried = [] -            here = os.path.abspath(os.path.dirname(__file__)) -            for i in range(10): -                up = ['..'] * i -                path = [here] + up + [name] -                fname = os.path.join(*path) -                fname = os.path.abspath(fname) -                tried.append(fname) -                if os.path.exists(fname): -                    return fname -            raise AssertionError("Could not find file " + name + "; checked " + str(tried)) - -        try: -            setup_py = find_dominating_file('setup.py') -        except AssertionError as e: -            self.skipTest("Unable to find setup.py; must be out of tree. " + str(e)) - - -        invoke_setup = "%s %s --version" % (sys.executable, setup_py) -        with os.popen(invoke_setup) as f: -            sversion = f.read().strip() - -        self.assertEqual(sversion, greenlet.__version__) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_weakref.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_weakref.py deleted file mode 100644 index 05a38a7..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_weakref.py +++ /dev/null @@ -1,35 +0,0 @@ -import gc -import weakref - - -import greenlet -from . import TestCase - -class WeakRefTests(TestCase): -    def test_dead_weakref(self): -        def _dead_greenlet(): -            g = greenlet.greenlet(lambda: None) -            g.switch() -            return g -        o = weakref.ref(_dead_greenlet()) -        gc.collect() -        self.assertEqual(o(), None) - -    def test_inactive_weakref(self): -        o = weakref.ref(greenlet.greenlet()) -        gc.collect() -        self.assertEqual(o(), None) - -    def test_dealloc_weakref(self): -        seen = [] -        def worker(): -            try: -                greenlet.getcurrent().parent.switch() -            finally: -                seen.append(g()) -        g = greenlet.greenlet(worker) -        g.switch() -        g2 = greenlet.greenlet(lambda: None, g) -        g = weakref.ref(g2) -        g2 = None -        self.assertEqual(seen, [None]) | 
