From 06bf9a29a4513cdfe43150172a1a8cf95c2abd40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 1 Jun 2022 11:26:36 +0200 Subject: [PATCH] Support Python 3.11 --- master...hroncok:py311b3.patch | 267 +++++++++++++++++++++++++++++++++ python-gevent.spec | 13 +- 2 files changed, 277 insertions(+), 3 deletions(-) create mode 100644 master...hroncok:py311b3.patch diff --git a/master...hroncok:py311b3.patch b/master...hroncok:py311b3.patch new file mode 100644 index 0000000..31dbd5c --- /dev/null +++ b/master...hroncok:py311b3.patch @@ -0,0 +1,267 @@ +From af14567992dfc709a6732ec8830e6840cb83f609 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= +Date: Wed, 8 Jun 2022 15:09:35 +0200 +Subject: [PATCH 1/3] Update greenlet for Python 3.11 + +From https://github.com/python-greenlet/greenlet/pull/306 + +Co-Authored-By: Victor Stinner +--- + deps/greenlet/greenlet.h | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/deps/greenlet/greenlet.h b/deps/greenlet/greenlet.h +index 830bef8dd..4a26ace78 100644 +--- a/deps/greenlet/greenlet.h ++++ b/deps/greenlet/greenlet.h +@@ -14,6 +14,15 @@ extern "C" { + /* This is deprecated and undocumented. It does not change. */ + #define GREENLET_VERSION "1.0.0" + ++#if PY_VERSION_HEX >= 0x30B00A6 ++# define GREENLET_PY311 1 ++/* We need this for _PyInterpreterFrame apparently */ ++#include ++#else ++#define GREENLET_PY311 0 ++#define _PyCFrame CFrame ++#endif ++ + typedef struct _greenlet { + PyObject_HEAD + char* stack_start; +@@ -25,6 +34,12 @@ typedef struct _greenlet { + PyObject* run_info; + struct _frame* top_frame; + int recursion_depth; ++#if GREENLET_PY311 ++ _PyInterpreterFrame *current_frame; ++ _PyStackChunk *datastack_chunk; ++ PyObject **datastack_top; ++ PyObject **datastack_limit; ++#endif + PyObject* weakreflist; + #if PY_VERSION_HEX >= 0x030700A3 + _PyErr_StackItem* exc_info; +@@ -39,7 +54,7 @@ typedef struct _greenlet { + PyObject* context; + #endif + #if PY_VERSION_HEX >= 0x30A00B1 +- CFrame* cframe; ++ _PyCFrame* cframe; + #endif + } PyGreenlet; + + +From 4c3c5842bfb2982bf8560821db723b354eeede66 Mon Sep 17 00:00:00 2001 +From: Victor Stinner +Date: Tue, 1 Mar 2022 22:28:40 +0100 +Subject: [PATCH 2/3] Add Python 3.11 beta 3 support + +Co-Authored-By: Petr Viktorin +--- + _setuputils.py | 3 ++ + src/gevent/_gevent_cgreenlet.pxd | 47 ++++++++++++++++++++------------ + src/gevent/greenlet.py | 3 +- + 3 files changed, 35 insertions(+), 18 deletions(-) + +diff --git a/_setuputils.py b/_setuputils.py +index 7257b3eea..62748571e 100644 +--- a/_setuputils.py ++++ b/_setuputils.py +@@ -244,6 +244,9 @@ def cythonize1(ext): + 'infer_types': True, + 'nonecheck': False, + }, ++ compile_time_env={ ++ 'PY39B1': sys.hexversion >= 0x030900B1, ++ }, + # The common_utility_include_dir (not well documented) + # causes Cython to emit separate files for much of the + # static support code. Each of the modules then includes +diff --git a/src/gevent/_gevent_cgreenlet.pxd b/src/gevent/_gevent_cgreenlet.pxd +index cbb81a638..06ca25e5c 100644 +--- a/src/gevent/_gevent_cgreenlet.pxd ++++ b/src/gevent/_gevent_cgreenlet.pxd +@@ -52,35 +52,48 @@ cdef inline void greenlet_init(): + PyGreenlet_Import() + _greenlet_imported = True + +-cdef extern from "Python.h": ++ctypedef object CodeType + +- ctypedef class types.CodeType [object PyCodeObject]: +- pass ++IF PY39B1: ++ ctypedef object FrameType + +-cdef extern from "frameobject.h": ++ cdef extern from "Python.h": ++ CodeType PyFrame_GetCode(FrameType frame) ++ void* PyFrame_GetBack(FrameType frame) ++ ++ELSE: ++ cdef extern from "frameobject.h": ++ ctypedef class types.FrameType [object PyFrameObject]: ++ # We don't have PyFrame_GetCode, need to use the pointer directly ++ cdef CodeType f_code + +- ctypedef class types.FrameType [object PyFrameObject]: +- cdef CodeType f_code +- # Accessing the f_lineno directly doesn't work. There is an accessor +- # function, PyFrame_GetLineNumber that is needed to turn the raw line number +- # into the executing line number. +- # cdef int f_lineno +- # We can't declare this in the object as an object, because it's +- # allowed to be NULL, and Cython can't handle that. +- # We have to go through the python machinery to get a +- # proper None instead, or use an inline function. +- cdef void* f_back ++ # We can't declare this in the object as an object, because it's ++ # allowed to be NULL, and Cython can't handle that. ++ # We have to go through the python machinery to get a ++ # proper None instead, or use a function. ++ cdef void* f_back + ++cdef extern from "frameobject.h": + int PyFrame_GetLineNumber(FrameType frame) + + @cython.nonecheck(False) + cdef inline FrameType get_f_back(FrameType frame): +- if frame.f_back != NULL: +- return frame.f_back ++ IF PY39B1: ++ f_back = PyFrame_GetBack(frame) ++ ELSE: ++ f_back = frame.f_back ++ if f_back != NULL: ++ return f_back + + cdef inline int get_f_lineno(FrameType frame): + return PyFrame_GetLineNumber(frame) + ++cdef inline CodeType get_f_code(FrameType frame): ++ IF PY39B1: ++ return PyFrame_GetCode(frame) ++ ELSE: ++ return frame.f_code ++ + cdef void _init() + + cdef class SpawnedLink: +diff --git a/src/gevent/greenlet.py b/src/gevent/greenlet.py +index bed12ed44..612a8fd3a 100644 +--- a/src/gevent/greenlet.py ++++ b/src/gevent/greenlet.py +@@ -58,6 +58,7 @@ + # Frame access + locals()['get_f_back'] = lambda frame: frame.f_back + locals()['get_f_lineno'] = lambda frame: frame.f_lineno ++locals()['get_f_code'] = lambda frame: frame.f_code + + if _PYPY: + import _continuation # pylint:disable=import-error +@@ -157,7 +158,7 @@ def _extract_stack(limit): + # Arguments are always passed to the constructor as Python objects, + # meaning we wind up boxing the f_lineno just to unbox it if we pass it. + # It's faster to simply assign once the object is created. +- older_Frame.f_code = frame.f_code ++ older_Frame.f_code = get_f_code(frame) + older_Frame.f_lineno = get_f_lineno(frame) # pylint:disable=undefined-variable + if newer_Frame is not None: + newer_Frame.f_back = older_Frame + +From 70ad874dc8d17da81b356d02b9772bee68898f1c Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Wed, 8 Jun 2022 15:08:45 +0200 +Subject: [PATCH 3/3] Amend tests for Python 3.11: No more U file mode, no more + inspect.getargspec() + +--- + src/gevent/testing/testcase.py | 15 ++++++++++----- + src/gevent/tests/test__fileobject.py | 16 +++++++++++++--- + 2 files changed, 23 insertions(+), 8 deletions(-) + +diff --git a/src/gevent/testing/testcase.py b/src/gevent/testing/testcase.py +index cd5db8033..e3a9775fc 100644 +--- a/src/gevent/testing/testcase.py ++++ b/src/gevent/testing/testcase.py +@@ -383,6 +383,7 @@ def assert_error(self, kind=None, value=None, error=None, where_type=None): + return error + + def assertMonkeyPatchedFuncSignatures(self, mod_name, func_names=(), exclude=()): ++ # If inspect.getfullargspec is not available, + # We use inspect.getargspec because it's the only thing available + # in Python 2.7, but it is deprecated + # pylint:disable=deprecated-method,too-many-locals +@@ -409,9 +410,13 @@ def assertMonkeyPatchedFuncSignatures(self, mod_name, func_names=(), exclude=()) + + try: + with warnings.catch_warnings(): +- warnings.simplefilter("ignore") +- gevent_sig = inspect.getargspec(gevent_func) +- sig = inspect.getargspec(func) ++ try: ++ getfullargspec = inspect.getfullargspec ++ except AttributeError: ++ warnings.simplefilter("ignore") ++ getfullargspec = inspect.getargspec ++ gevent_sig = getfullargspec(gevent_func) ++ sig = getfullargspec(func) + except TypeError: + if funcs_given: + raise +@@ -420,10 +425,10 @@ def assertMonkeyPatchedFuncSignatures(self, mod_name, func_names=(), exclude=()) + # Python 3 can check a lot more than Python 2 can. + continue + self.assertEqual(sig.args, gevent_sig.args, func_name) +- # The next three might not actually matter? ++ # The next two might not actually matter? + self.assertEqual(sig.varargs, gevent_sig.varargs, func_name) +- self.assertEqual(sig.keywords, gevent_sig.keywords, func_name) + self.assertEqual(sig.defaults, gevent_sig.defaults, func_name) ++ # Should deal with others: https://docs.python.org/3/library/inspect.html#inspect.getfullargspec + + def assertEqualFlakyRaceCondition(self, a, b): + try: +diff --git a/src/gevent/tests/test__fileobject.py b/src/gevent/tests/test__fileobject.py +index afe8d7479..1f4e664a0 100644 +--- a/src/gevent/tests/test__fileobject.py ++++ b/src/gevent/tests/test__fileobject.py +@@ -200,6 +200,8 @@ def test_does_not_leak_on_exception(self): + + @skipUnlessWorksWithRegularFiles + def test_rbU_produces_bytes_readline(self): ++ if sys.version_info > (3, 11): ++ self.skipTest("U file mode was removed in 3.11") + # Including U in rb still produces bytes. + # Note that the universal newline behaviour is + # essentially ignored in explicit bytes mode. +@@ -213,6 +215,8 @@ def test_rbU_produces_bytes_readline(self): + + @skipUnlessWorksWithRegularFiles + def test_rU_produces_native(self): ++ if sys.version_info > (3, 11): ++ self.skipTest("U file mode was removed in 3.11") + gevent_data = self.__check_native_matches( + b'line1\nline2\r\nline3\rlastline\n\n', + 'rU', +@@ -362,9 +366,15 @@ def test_newlines(self): + + try: + with warnings.catch_warnings(): +- warnings.simplefilter('ignore', DeprecationWarning) +- # U is deprecated in Python 3, shows up on FileObjectThread +- fobj = self._makeOne(r, 'rU') ++ if sys.version_info > (3, 11): ++ # U is removed in Python 3.11 ++ mode = 'r' ++ self.skipTest("U file mode was removed in 3.11") ++ else: ++ # U is deprecated in Python 3, shows up on FileObjectThread ++ warnings.simplefilter('ignore', DeprecationWarning) ++ mode = 'rU' ++ fobj = self._makeOne(r, mode) + result = fobj.read() + fobj.close() + self.assertEqual('line1\nline2\nline3\nline4\nline5\nline6', result) diff --git a/python-gevent.spec b/python-gevent.spec index 5da01e9..c73b031 100644 --- a/python-gevent.spec +++ b/python-gevent.spec @@ -4,13 +4,17 @@ Name: python-%{modname} Version: 21.12.0 -Release: 1%{?dist} +Release: 2%{?dist} Summary: A coroutine-based Python networking library License: MIT URL: http://www.gevent.org/ Source0: %{pypi_source %{modname} %{version} tar.gz} +# Support Python 3.11 +# Discussion in https://github.com/gevent/gevent/pull/1872.patch +Patch: https://github.com/gevent/gevent/compare/master...hroncok:py311b3.patch + BuildRequires: gcc BuildRequires: c-ares-devel BuildRequires: libev-devel @@ -34,14 +38,13 @@ Summary: %{summary} %{?python_provide:%python_provide python3-%{modname}} BuildRequires: python3-devel BuildRequires: python3-Cython -BuildRequires: python3-greenlet-devel >= 0.4.17 +BuildRequires: python3-greenlet-devel >= 1.1.0 BuildRequires: python3-setuptools # For tests BuildRequires: python3-dns BuildRequires: python3-psutil BuildRequires: python3-zope-event BuildRequires: python3-zope-interface -Requires: python3-greenlet >= 0.4.17 %description -n python3-%{modname} gevent is a coroutine-based Python networking library that uses greenlet to @@ -69,6 +72,7 @@ sed -i -e 's/include_package_data=True/include_package_data=False/' setup.py # Force re-cythonizing the sources rm $(grep -rl '/\* Generated by Cython') +rm src/gevent/_generated_include/* %build export GEVENTSETUP_EMBED=0 @@ -95,6 +99,9 @@ cd src/gevent/tests && GEVENT_FILE=thread %__python3 -mgevent.tests test__*subpr %{python3_sitearch}/%{modname}* %changelog +* Wed Jun 01 2022 Miro HronĨok - 21.12.0-2 +- Support Python 3.11 + * Sun Mar 06 2022 Orion Poplawski - 21.12.0-1 - Update to 21.12.0