From e11873ff48895e3e2d613cc2c2f34e69d6bf4158 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Wed, 14 Jun 2023 18:00:07 +0200 Subject: [PATCH] Update to upstream version 2.0.2 - Update to upstream version 2.0.2 - Add patch for Python 3.12 compatibility - Skip leak checks for now --- .gitignore | 1 + 327.patch | 503 ++++++++++++++++++ ...-limits-to-add-compatibility-with-Py.patch | 74 --- python-greenlet.spec | 25 +- skip-leak-checks.patch | 291 ++++++++++ sources | 2 +- 6 files changed, 816 insertions(+), 80 deletions(-) create mode 100644 327.patch delete mode 100644 Rename-recursion-limits-to-add-compatibility-with-Py.patch create mode 100644 skip-leak-checks.patch diff --git a/.gitignore b/.gitignore index efa9643..e6e9d0c 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ greenlet-0.3.1.tar.gz /greenlet-1.1.1.tar.gz /greenlet-1.1.2.tar.gz /greenlet-1.1.3.tar.gz +/greenlet-2.0.2.tar.gz diff --git a/327.patch b/327.patch new file mode 100644 index 0000000..31a0bec --- /dev/null +++ b/327.patch @@ -0,0 +1,503 @@ +From 0418516101d92159f74e69fdd1c29010db71c5cc Mon Sep 17 00:00:00 2001 +From: Thomas A Caswell +Date: Fri, 4 Nov 2022 11:11:58 -0400 +Subject: [PATCH 01/12] Fix #323: Support Python 3.12 + +--- + src/greenlet/greenlet_cpython_compat.hpp | 6 ++++++ + src/greenlet/greenlet_greenlet.hpp | 12 +++++++++++- + 2 files changed, 17 insertions(+), 1 deletion(-) + +diff --git a/src/greenlet/greenlet_cpython_compat.hpp b/src/greenlet/greenlet_cpython_compat.hpp +index 3fd13ac..6210586 100644 +--- a/src/greenlet/greenlet_cpython_compat.hpp ++++ b/src/greenlet/greenlet_cpython_compat.hpp +@@ -48,6 +48,12 @@ We have to save and restore this as well. + # define GREENLET_USE_CFRAME 0 + #endif + ++#if PY_VERSION_HEX >= 0x30C0000 ++# define GREENLET_PY312 1 ++#else ++# define GREENLET_PY312 0 ++#endif ++ + #if PY_VERSION_HEX >= 0x30B00A4 + /* + Greenlet won't compile on anything older than Python 3.11 alpha 4 (see +diff --git a/src/greenlet/greenlet_greenlet.hpp b/src/greenlet/greenlet_greenlet.hpp +index cc02c5c..472902e 100644 +--- a/src/greenlet/greenlet_greenlet.hpp ++++ b/src/greenlet/greenlet_greenlet.hpp +@@ -831,7 +831,11 @@ void PythonState::operator<<(const PyThreadState *const tstate) G_NOEXCEPT + this->use_tracing = tstate->cframe->use_tracing; + #endif + #if GREENLET_PY311 ++ #if GREENLET_PY312 ++ this->recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; ++ #else + this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; ++ #endif + this->current_frame = tstate->cframe->current_frame; + this->datastack_chunk = tstate->datastack_chunk; + this->datastack_top = tstate->datastack_top; +@@ -867,7 +871,11 @@ void PythonState::operator>>(PyThreadState *const tstate) G_NOEXCEPT + tstate->cframe->use_tracing = this->use_tracing; + #endif + #if GREENLET_PY311 ++ #if GREENLET_PY312 ++ tstate->py_recursion_remaining = tstate->py_recursion_limit - this->recursion_depth; ++ #else + tstate->recursion_remaining = tstate->recursion_limit - this->recursion_depth; ++ #endif + tstate->cframe->current_frame = this->current_frame; + tstate->datastack_chunk = this->datastack_chunk; + tstate->datastack_top = this->datastack_top; +@@ -895,7 +903,9 @@ void PythonState::will_switch_from(PyThreadState *const origin_tstate) G_NOEXCEP + void PythonState::set_initial_state(const PyThreadState* const tstate) G_NOEXCEPT + { + this->_top_frame = nullptr; +-#if GREENLET_PY311 ++#if GREENLET_PY312 ++ this->recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; ++#elif GREENLET_PY311 + this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; + #else + this->recursion_depth = tstate->recursion_depth; + +From 5c76aeda3709cafc8afe656ed7fa284369059d98 Mon Sep 17 00:00:00 2001 +From: Michael Droettboom +Date: Fri, 4 Nov 2022 12:53:37 -0400 +Subject: [PATCH 02/12] Fix 3.12 testing + +--- + .github/workflows/tests.yml | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml +index 27c91e0..237a85b 100644 +--- a/.github/workflows/tests.yml ++++ b/.github/workflows/tests.yml +@@ -25,15 +25,23 @@ jobs: + runs-on: ${{ matrix.os }} + strategy: + matrix: +- python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9, "3.10", "3.11"] ++ python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9, "3.10", "3.11", "3.12.0~a1"] + # Jan 2023: We have pinned back from ubuntu-latest (which is + # now ubuntu 22.04) because older Python versions like + # 3.5, 3.6 and presumably 2.7 are not available in it. +- os: [ubuntu-20.04, macos-latest] ++ os: [ubuntu-latest, macos-latest] ++ exclude: ++ - os: macos-latest ++ python-version: 3.12.0~a1 + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 ++ if: "!contains(matrix.python-version, '~')" ++ with: ++ python-version: ${{ matrix.python-version }} ++ - uses: deadsnakes/action@v2.1.1 ++ if: "contains(matrix.python-version, '~')" + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + +From dbe67e389158a5120bcaee857ce9df8d8e20240f Mon Sep 17 00:00:00 2001 +From: Michael Droettboom +Date: Fri, 4 Nov 2022 12:56:25 -0400 +Subject: [PATCH 03/12] Try a different way to specify version + +--- + .github/workflows/tests.yml | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml +index 237a85b..7d3c3d4 100644 +--- a/.github/workflows/tests.yml ++++ b/.github/workflows/tests.yml +@@ -25,23 +25,23 @@ jobs: + runs-on: ${{ matrix.os }} + strategy: + matrix: +- python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9, "3.10", "3.11", "3.12.0~a1"] ++ python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9, "3.10", "3.11", "3.12"] + # Jan 2023: We have pinned back from ubuntu-latest (which is + # now ubuntu 22.04) because older Python versions like + # 3.5, 3.6 and presumably 2.7 are not available in it. + os: [ubuntu-latest, macos-latest] + exclude: + - os: macos-latest +- python-version: 3.12.0~a1 ++ python-version: 3.12 + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 +- if: "!contains(matrix.python-version, '~')" ++ if: "!equals(matrix.python-version, '3.12')" + with: + python-version: ${{ matrix.python-version }} + - uses: deadsnakes/action@v2.1.1 +- if: "contains(matrix.python-version, '~')" ++ if: "equals(matrix.python-version, '3.12')" + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + +From 8d0cb88cfba16226e5a5936b3f48d838a15fbe28 Mon Sep 17 00:00:00 2001 +From: Michael Droettboom +Date: Fri, 4 Nov 2022 14:20:47 -0400 +Subject: [PATCH 04/12] Fix syntax + +--- + .github/workflows/tests.yml | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml +index 7d3c3d4..90897af 100644 +--- a/.github/workflows/tests.yml ++++ b/.github/workflows/tests.yml +@@ -37,11 +37,11 @@ jobs: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 +- if: "!equals(matrix.python-version, '3.12')" ++ if: "matrix.python-version != '3.12'" + with: + python-version: ${{ matrix.python-version }} + - uses: deadsnakes/action@v2.1.1 +- if: "equals(matrix.python-version, '3.12')" ++ if: "matrix.python-version == '3.12'" + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + +From 51a334e65dafb171742f5a715ad89c3116900c04 Mon Sep 17 00:00:00 2001 +From: Michael Droettboom +Date: Wed, 16 Nov 2022 09:14:29 -0500 +Subject: [PATCH 05/12] Use 3.12-dev instead of deadsnakes + +Co-authored-by: Andreas Motl +--- + .github/workflows/tests.yml | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml +index 90897af..060cc7f 100644 +--- a/.github/workflows/tests.yml ++++ b/.github/workflows/tests.yml +@@ -25,23 +25,18 @@ jobs: + runs-on: ${{ matrix.os }} + strategy: + matrix: +- python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9, "3.10", "3.11", "3.12"] ++ python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9, "3.10", "3.11", "3.12-dev"] + # Jan 2023: We have pinned back from ubuntu-latest (which is + # now ubuntu 22.04) because older Python versions like + # 3.5, 3.6 and presumably 2.7 are not available in it. + os: [ubuntu-latest, macos-latest] + exclude: + - os: macos-latest +- python-version: 3.12 ++ python-version: 3.12-dev + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 +- if: "matrix.python-version != '3.12'" +- with: +- python-version: ${{ matrix.python-version }} +- - uses: deadsnakes/action@v2.1.1 +- if: "matrix.python-version == '3.12'" + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + +From 387dee06179373e53b2d42447ea88f2acdcd2d1f Mon Sep 17 00:00:00 2001 +From: Michael Droettboom +Date: Thu, 27 Apr 2023 09:52:14 -0400 +Subject: [PATCH 06/12] Updates for PEP669 + +--- + src/greenlet/greenlet.cpp | 4 ++++ + src/greenlet/greenlet_greenlet.hpp | 15 +++++++++------ + 2 files changed, 13 insertions(+), 6 deletions(-) + +diff --git a/src/greenlet/greenlet.cpp b/src/greenlet/greenlet.cpp +index 1d6ddaa..b382c5a 100644 +--- a/src/greenlet/greenlet.cpp ++++ b/src/greenlet/greenlet.cpp +@@ -3092,7 +3092,11 @@ static PyObject* + mod_get_tstate_trash_delete_nesting(PyObject* UNUSED(module)) + { + PyThreadState* tstate = PyThreadState_GET(); ++#if GREENLET_PY312 ++ return PyLong_FromLong(tstate->trash.delete_nesting); ++#else + return PyLong_FromLong(tstate->trash_delete_nesting); ++#endif + } + + static PyMethodDef GreenMethods[] = { +diff --git a/src/greenlet/greenlet_greenlet.hpp b/src/greenlet/greenlet_greenlet.hpp +index 472902e..7146214 100644 +--- a/src/greenlet/greenlet_greenlet.hpp ++++ b/src/greenlet/greenlet_greenlet.hpp +@@ -828,7 +828,9 @@ void PythonState::operator<<(const PyThreadState *const tstate) G_NOEXCEPT + the switch, use `will_switch_from`. + */ + this->cframe = tstate->cframe; ++ #if !GREENLET_PY312 + this->use_tracing = tstate->cframe->use_tracing; ++ #endif + #endif + #if GREENLET_PY311 + #if GREENLET_PY312 +@@ -843,13 +845,12 @@ void PythonState::operator<<(const PyThreadState *const tstate) G_NOEXCEPT + PyFrameObject *frame = PyThreadState_GetFrame((PyThreadState *)tstate); + Py_XDECREF(frame); // PyThreadState_GetFrame gives us a new reference. + this->_top_frame.steal(frame); ++ this->trash_delete_nesting = tstate->trash.delete_nesting; + #else + this->recursion_depth = tstate->recursion_depth; + this->_top_frame.steal(tstate->frame); +-#endif +- +- // All versions of Python. + this->trash_delete_nesting = tstate->trash_delete_nesting; ++#endif + } + + void PythonState::operator>>(PyThreadState *const tstate) G_NOEXCEPT +@@ -868,7 +869,9 @@ void PythonState::operator>>(PyThreadState *const tstate) G_NOEXCEPT + root_cframe here. See note above about why we can't + just copy this from ``origin->cframe->use_tracing``. + */ ++ #if !GREENLET_PY312 + tstate->cframe->use_tracing = this->use_tracing; ++ #endif + #endif + #if GREENLET_PY311 + #if GREENLET_PY312 +@@ -881,17 +884,17 @@ void PythonState::operator>>(PyThreadState *const tstate) G_NOEXCEPT + tstate->datastack_top = this->datastack_top; + tstate->datastack_limit = this->datastack_limit; + this->_top_frame.relinquish_ownership(); ++ tstate->trash.delete_nesting = this->trash_delete_nesting; + #else + tstate->frame = this->_top_frame.relinquish_ownership(); + tstate->recursion_depth = this->recursion_depth; ++ tstate->trash.delete_nesting = this->trash_delete_nesting; + #endif +- // All versions of Python. +- tstate->trash_delete_nesting = this->trash_delete_nesting; + } + + void PythonState::will_switch_from(PyThreadState *const origin_tstate) G_NOEXCEPT + { +-#if GREENLET_USE_CFRAME ++#if GREENLET_USE_CFRAME && !GREENLET_PY312 + // The weird thing is, we don't actually save this for an + // effect on the current greenlet, it's saved for an + // effect on the target greenlet. That is, we want + +From db74f88454dd36c3c6769bec680a16a1ac284b96 Mon Sep 17 00:00:00 2001 +From: Michael Droettboom +Date: Thu, 27 Apr 2023 09:54:50 -0400 +Subject: [PATCH 07/12] Fix Python 3.11 + +--- + src/greenlet/greenlet_greenlet.hpp | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/greenlet/greenlet_greenlet.hpp b/src/greenlet/greenlet_greenlet.hpp +index 7146214..41fda8e 100644 +--- a/src/greenlet/greenlet_greenlet.hpp ++++ b/src/greenlet/greenlet_greenlet.hpp +@@ -845,7 +845,11 @@ void PythonState::operator<<(const PyThreadState *const tstate) G_NOEXCEPT + PyFrameObject *frame = PyThreadState_GetFrame((PyThreadState *)tstate); + Py_XDECREF(frame); // PyThreadState_GetFrame gives us a new reference. + this->_top_frame.steal(frame); ++ #if GREENLET_PY312 + this->trash_delete_nesting = tstate->trash.delete_nesting; ++ #else ++ this->trash_delete_nesting = tstate->trash_delete_nesting; ++ #endif + #else + this->recursion_depth = tstate->recursion_depth; + this->_top_frame.steal(tstate->frame); +@@ -884,7 +888,11 @@ void PythonState::operator>>(PyThreadState *const tstate) G_NOEXCEPT + tstate->datastack_top = this->datastack_top; + tstate->datastack_limit = this->datastack_limit; + this->_top_frame.relinquish_ownership(); ++ #if GREENLET_PY312 + tstate->trash.delete_nesting = this->trash_delete_nesting; ++ #else ++ tstate->trash_delete_nesting = this->trash_delete_nesting; ++ #endif + #else + tstate->frame = this->_top_frame.relinquish_ownership(); + tstate->recursion_depth = this->recursion_depth; + +From 132c4616f38e3c05899da1be22086d96e4981057 Mon Sep 17 00:00:00 2001 +From: Michael Droettboom +Date: Thu, 27 Apr 2023 09:56:56 -0400 +Subject: [PATCH 08/12] Revert ubuntu-latest change + +--- + .github/workflows/tests.yml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml +index 060cc7f..fa48066 100644 +--- a/.github/workflows/tests.yml ++++ b/.github/workflows/tests.yml +@@ -29,7 +29,7 @@ jobs: + # Jan 2023: We have pinned back from ubuntu-latest (which is + # now ubuntu 22.04) because older Python versions like + # 3.5, 3.6 and presumably 2.7 are not available in it. +- os: [ubuntu-latest, macos-latest] ++ os: [ubuntu-20.04, macos-latest] + exclude: + - os: macos-latest + python-version: 3.12-dev + +From d26952ec3fb74c1f1d68104a4ac80018deb0618c Mon Sep 17 00:00:00 2001 +From: Michael Droettboom +Date: Thu, 27 Apr 2023 09:58:22 -0400 +Subject: [PATCH 09/12] Fix legacy versions + +--- + src/greenlet/greenlet_greenlet.hpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/greenlet/greenlet_greenlet.hpp b/src/greenlet/greenlet_greenlet.hpp +index 41fda8e..ffb23a7 100644 +--- a/src/greenlet/greenlet_greenlet.hpp ++++ b/src/greenlet/greenlet_greenlet.hpp +@@ -896,7 +896,7 @@ void PythonState::operator>>(PyThreadState *const tstate) G_NOEXCEPT + #else + tstate->frame = this->_top_frame.relinquish_ownership(); + tstate->recursion_depth = this->recursion_depth; +- tstate->trash.delete_nesting = this->trash_delete_nesting; ++ tstate->trash_delete_nesting = this->trash_delete_nesting; + #endif + } + + +From 82f9a8869d88616decb777bc6afae3a751a4a9c0 Mon Sep 17 00:00:00 2001 +From: Michael Droettboom +Date: Thu, 27 Apr 2023 17:29:10 -0400 +Subject: [PATCH 10/12] Print precise Python version + +--- + .github/workflows/tests.yml | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml +index fa48066..aa14318 100644 +--- a/.github/workflows/tests.yml ++++ b/.github/workflows/tests.yml +@@ -80,6 +80,7 @@ jobs: + path: dist/*whl + - name: Test + run: | ++ python -VV + python -c 'import greenlet._greenlet as G; assert G.GREENLET_USE_STANDARD_THREADING' + python -m unittest discover -v greenlet.tests + - name: Doctest + +From 3629e46c49533a994aa8f12ed3b41ae6725ab2ce Mon Sep 17 00:00:00 2001 +From: Michael Droettboom +Date: Tue, 2 May 2023 10:48:37 -0400 +Subject: [PATCH 11/12] Fix recursion depth updating + +--- + src/greenlet/greenlet_greenlet.hpp | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/src/greenlet/greenlet_greenlet.hpp b/src/greenlet/greenlet_greenlet.hpp +index ffb23a7..10244e0 100644 +--- a/src/greenlet/greenlet_greenlet.hpp ++++ b/src/greenlet/greenlet_greenlet.hpp +@@ -143,7 +143,12 @@ namespace greenlet + _PyCFrame* cframe; + int use_tracing; + #endif ++#if GREENLET_PY312 ++ int py_recursion_depth; ++ int c_recursion_depth; ++#else + int recursion_depth; ++#endif + int trash_delete_nesting; + #if GREENLET_PY311 + _PyInterpreterFrame* current_frame; +@@ -748,7 +753,12 @@ PythonState::PythonState() + ,cframe(nullptr) + ,use_tracing(0) + #endif ++#if GREENLET_PY312 ++ ,py_recursion_depth(0) ++ ,c_recursion_depth(0) ++#else + ,recursion_depth(0) ++#endif + ,trash_delete_nesting(0) + #if GREENLET_PY311 + ,current_frame(nullptr) +@@ -834,7 +844,8 @@ void PythonState::operator<<(const PyThreadState *const tstate) G_NOEXCEPT + #endif + #if GREENLET_PY311 + #if GREENLET_PY312 +- this->recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; ++ this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; ++ this->c_recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining; + #else + this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; + #endif +@@ -879,7 +890,8 @@ void PythonState::operator>>(PyThreadState *const tstate) G_NOEXCEPT + #endif + #if GREENLET_PY311 + #if GREENLET_PY312 +- tstate->py_recursion_remaining = tstate->py_recursion_limit - this->recursion_depth; ++ tstate->py_recursion_remaining = tstate->py_recursion_limit - this->py_recursion_depth; ++ tstate->c_recursion_remaining = C_RECURSION_LIMIT - this->c_recursion_depth; + #else + tstate->recursion_remaining = tstate->recursion_limit - this->recursion_depth; + #endif +@@ -915,7 +927,8 @@ void PythonState::set_initial_state(const PyThreadState* const tstate) G_NOEXCEP + { + this->_top_frame = nullptr; + #if GREENLET_PY312 +- this->recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; ++ this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; ++ this->c_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; + #elif GREENLET_PY311 + this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; + #else + +From 6bba85fdfd0acd1484780fae7a537e3dac99c067 Mon Sep 17 00:00:00 2001 +From: Michael Droettboom +Date: Tue, 30 May 2023 12:14:22 -0400 +Subject: [PATCH 12/12] Insert blank line + +--- + src/greenlet/greenlet.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/greenlet/greenlet.cpp b/src/greenlet/greenlet.cpp +index b382c5a..677fce8 100644 +--- a/src/greenlet/greenlet.cpp ++++ b/src/greenlet/greenlet.cpp +@@ -3092,6 +3092,7 @@ static PyObject* + mod_get_tstate_trash_delete_nesting(PyObject* UNUSED(module)) + { + PyThreadState* tstate = PyThreadState_GET(); ++ + #if GREENLET_PY312 + return PyLong_FromLong(tstate->trash.delete_nesting); + #else diff --git a/Rename-recursion-limits-to-add-compatibility-with-Py.patch b/Rename-recursion-limits-to-add-compatibility-with-Py.patch deleted file mode 100644 index 475181d..0000000 --- a/Rename-recursion-limits-to-add-compatibility-with-Py.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 6d2e3a9e8d5ca1e735301824fd2a7136db9eeb81 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= -Date: Fri, 17 Mar 2023 11:59:10 +0100 -Subject: [PATCH] Rename recursion limits to add compatibility with Python 3.12 - ---- - src/greenlet/greenlet.c | 19 ++++++++++++++++--- - src/greenlet/greenlet.h | 6 ++++++ - 2 files changed, 22 insertions(+), 3 deletions(-) - -diff --git a/src/greenlet/greenlet.c b/src/greenlet/greenlet.c -index 2f3ad6e..6165064 100644 ---- a/src/greenlet/greenlet.c -+++ b/src/greenlet/greenlet.c -@@ -527,7 +527,10 @@ g_switchstack(void) - { /* save state */ - PyGreenlet* current = ts_current; - PyThreadState* tstate = PyThreadState_GET(); --#if GREENLET_PY311 -+#if GREENLET_PY312 -+ current->recursion_depth = (tstate->py_recursion_limit -+ - tstate->py_recursion_remaining); -+#elif GREENLET_PY311 - current->recursion_depth = (tstate->recursion_limit - - tstate->recursion_remaining); - #else -@@ -620,7 +623,14 @@ g_switchstack(void) - */ - tstate->cframe->use_tracing = ts__g_switchstack_use_tracing; - #endif --#if GREENLET_PY311 -+#if GREENLET_PY312 -+ tstate->py_recursion_remaining = (tstate->py_recursion_limit -+ - target->recursion_depth); -+ tstate->cframe->current_frame = target->current_frame; -+ tstate->datastack_chunk = target->datastack_chunk; -+ tstate->datastack_top = target->datastack_top; -+ tstate->datastack_limit = target->datastack_limit; -+#elif GREENLET_PY311 - tstate->recursion_remaining = (tstate->recursion_limit - - target->recursion_depth); - tstate->cframe->current_frame = target->current_frame; -@@ -899,7 +909,10 @@ static int GREENLET_NOINLINE(g_initialstub)(void* mark) - } - self->top_frame = NULL; - green_clear_exc(self); --#if GREENLET_PY311 -+#if GREENLET_PY312 -+ self->recursion_depth = (PyThreadState_GET()->py_recursion_limit -+ - PyThreadState_GET()->py_recursion_remaining); -+#elif GREENLET_PY311 - self->recursion_depth = (PyThreadState_GET()->recursion_limit - - PyThreadState_GET()->recursion_remaining); - #else -diff --git a/src/greenlet/greenlet.h b/src/greenlet/greenlet.h -index c788b2f..e20c580 100644 ---- a/src/greenlet/greenlet.h -+++ b/src/greenlet/greenlet.h -@@ -23,6 +23,12 @@ extern "C" { - # define _PyCFrame CFrame - #endif - -+#if PY_VERSION_HEX >= 0x30C00A6 -+# define GREENLET_PY312 1 -+#else -+# define GREENLET_PY312 0 -+#endif -+ - typedef struct _greenlet { - PyObject_HEAD - char* stack_start; --- -2.38.1 - diff --git a/python-greenlet.spec b/python-greenlet.spec index 4f64dfe..b3d532d 100644 --- a/python-greenlet.spec +++ b/python-greenlet.spec @@ -1,16 +1,19 @@ %global modname greenlet Name: python-%{modname} -Version: 1.1.3 -Release: 3%{?dist} +Version: 2.0.2 +Release: 1%{?dist} Summary: Lightweight in-process concurrent programming License: MIT URL: https://github.com/python-greenlet/greenlet Source0: %{url}/archive/%{version}/%{modname}-%{version}.tar.gz # Patch needed for compatibility with Python 3.12 -# Inspired by: https://github.com/python-greenlet/greenlet/issues/323#issue-1428384781 -Patch: Rename-recursion-limits-to-add-compatibility-with-Py.patch +# From: https://github.com/python-greenlet/greenlet/pull/327 +Patch: https://github.com/python-greenlet/greenlet/pull/327.patch + +# Skip leak checking to avoid a missing dependency, `objgraph` +Patch: skip-leak-checks.patch BuildRequires: gcc-c++ @@ -28,6 +31,9 @@ Summary: %{summary} BuildRequires: python3-devel BuildRequires: python3-setuptools +# For tests +BuildRequires: python3-psutil + %description -n python3-%{modname} %{_description} Python 3 version. @@ -52,7 +58,11 @@ Python 3 version. %py3_install %check -PYTHONPATH="%{buildroot}%{python3_sitearch}" %{python3} -m unittest discover greenlet.tests +cd / +PYTHONPATH="%{buildroot}%{python3_sitearch}" \ + %{python3} -m unittest discover -v \ + -s "%{buildroot}%{python3_sitearch}/greenlet/tests" \ + -t "%{buildroot}%{python3_sitearch}" %files -n python3-%{modname} %license LICENSE LICENSE.PSF @@ -64,6 +74,11 @@ PYTHONPATH="%{buildroot}%{python3_sitearch}" %{python3} -m unittest discover gre %{_includedir}/python%{python3_version}*/%{modname}/ %changelog +* Wed Jun 14 2023 Petr Viktorin - 2.0.2-1 +- Update to upstream version 2.0.2 +- Update patch for Python 3.12 compatibility +- Skip leak checks for now + * Tue Jun 13 2023 Python Maint - 1.1.3-3 - Rebuilt for Python 3.12 diff --git a/skip-leak-checks.patch b/skip-leak-checks.patch new file mode 100644 index 0000000..83228d5 --- /dev/null +++ b/skip-leak-checks.patch @@ -0,0 +1,291 @@ +diff -rU3 greenlet-2.0.2-orig/src/greenlet/tests/leakcheck.py greenlet-2.0.2/src/greenlet/tests/leakcheck.py +--- greenlet-2.0.2-orig/src/greenlet/tests/leakcheck.py 2023-01-28 15:19:12.000000000 +0100 ++++ greenlet-2.0.2/src/greenlet/tests/leakcheck.py 2023-06-14 17:49:32.395412453 +0200 +@@ -30,39 +30,7 @@ + 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. ++# Edited for Fedora to avoid missing dependency + + RUNNING_ON_GITHUB_ACTIONS = os.environ.get('GITHUB_ACTIONS') + RUNNING_ON_TRAVIS = os.environ.get('TRAVIS') or RUNNING_ON_GITHUB_ACTIONS +@@ -74,53 +42,15 @@ + 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 ++fails_strict_leakcheck = fails_leakcheck + + class ignores_types_in_strict_leakcheck(object): + def __init__(self, types): +@@ -129,190 +59,5 @@ + 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 "" +- +- 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 +- 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 ++ return method diff --git a/sources b/sources index e03cd60..1a884c1 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (greenlet-1.1.3.tar.gz) = 6fbb00f7717c96c429c645606ce6a2b1487ac081c4b75a906766479c18c0b74165a95bd55754803aa532662cf033f269ac80ecb0f17c4ba2e00a0b168849db88 +SHA512 (greenlet-2.0.2.tar.gz) = 4817fa870a8c40c86a63d17edc870cb6514d074ff3e1a99b6319ec3124f5cb22146b036f0a4f5dd39d003c81eace894c6b89abc6d562c40558ea2d5351c89103