Skip to content

Commit

Permalink
Merge pull request #1908 from gevent/jam-py311-wip
Browse files Browse the repository at this point in the history
Python 3.11rc2 support
  • Loading branch information
jamadden committed Oct 8, 2022
2 parents e29bd2e + 7327657 commit 65417fe
Show file tree
Hide file tree
Showing 73 changed files with 29,150 additions and 104 deletions.
16 changes: 10 additions & 6 deletions .github/workflows/ci.yml
Expand Up @@ -148,7 +148,7 @@ jobs:
# 3.10 needs more work: dnspython for example doesn't work
# with it. That means for the bulk of our testing we need to
# stick to 3.9.
python-version: [2.7, pypy-2.7, pypy-3.7, 3.6, 3.7, 3.8, 3.9, '3.10']
python-version: [2.7, pypy-2.7, pypy-3.7, 3.6, 3.7, 3.8, 3.9, '3.10', '3.11.0-rc.2']
# ubuntu-latest is at least 20.04. But this breaks the SSL
# tests because Ubuntu increased the default OpenSSL
# strictness.
Expand Down Expand Up @@ -178,6 +178,8 @@ jobs:
python-version: 3.9
- os: ubuntu-18.04
python-version: '3.10'
- os: ubuntu-18.04
python-version: '3.11.0-rc.2'
steps:
- name: checkout
uses: actions/checkout@v2
Expand Down Expand Up @@ -341,15 +343,17 @@ jobs:
run: |
python -mgevent.tests --second-chance $G_USE_COV --ignore tests_that_dont_use_resolver.txt
- name: "Tests: dnspython resolver"
# This has known issues on Pypy-3.6. Also, save mac minutes.
if: (matrix.python-version == 2.7 || matrix.python-version == '3.9') && startsWith(runner.os, 'Linux')
# This has known issues on Pypy-3.6.
if: (matrix.python-version == '3.9') && startsWith(runner.os, 'Linux')
env:
GEVENT_RESOLVER: dnspython
run: |
python -mgevent.tests --second-chance $G_USE_COV --ignore tests_that_dont_use_resolver.txt
- name: "Tests: leakchecks"
# Run the leaktests; this seems to be extremely slow on Python 3.7
# XXX: Figure out why. Can we reproduce locally?
# This is incredibly important and we MUST have an environment that successfully passes
# these tests.
if: matrix.python-version == 2.7 && startsWith(runner.os, 'Linux')
env:
GEVENTTEST_LEAKCHECK: 1
Expand All @@ -358,7 +362,7 @@ jobs:
- name: "Tests: PURE_PYTHON"
# No compiled cython modules on CPython, using the default backend. Get coverage here.
# We should only need to run this for a single Python 2 and a Python 3
if: (matrix.python-version == 2.7 || matrix.python-version == '3.9') && startsWith(runner.os, 'Linux')
if: (matrix.python-version == '3.9') && startsWith(runner.os, 'Linux')
env:
PURE_PYTHON: 1
run: |
Expand Down Expand Up @@ -400,8 +404,8 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: [2.7, '3.9']
os: [ubuntu-18.04]
python-version: ['3.9']
os: [ubuntu-latest]
steps:
- name: checkout
uses: actions/checkout@v2
Expand Down
17 changes: 17 additions & 0 deletions _setuputils.py
Expand Up @@ -244,6 +244,23 @@ def cythonize1(ext):
'infer_types': True,
'nonecheck': False,
},
# XXX: Cython developers say: "Please use C macros instead
# of Pyrex defines. Taking this kind of decision based on
# the runtime environment of the build is wrong, it needs
# to be taken at C compile time."
#
# They also say, "The 'IF' statement is deprecated and
# will be removed in a future Cython version. Consider
# using runtime conditions or C macros instead. See
# https://github.com/cython/cython/issues/4310"
#
# And: " The 'DEF' statement is deprecated and will be
# removed in a future Cython version. Consider using
# global variables, constants, and in-place literals
# instead."
#compile_time_env={
#
#},
# 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
Expand Down
17 changes: 16 additions & 1 deletion deps/greenlet/greenlet.h
Expand Up @@ -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
/* _PyInterpreterFrame moved to the internal C API in Python 3.11 */
# include <internal/pycore_frame.h>
#else
# define GREENLET_PY311 0
# define _PyCFrame CFrame
#endif

typedef struct _greenlet {
PyObject_HEAD
char* stack_start;
Expand All @@ -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;
Expand All @@ -39,7 +54,7 @@ typedef struct _greenlet {
PyObject* context;
#endif
#if PY_VERSION_HEX >= 0x30A00B1
CFrame* cframe;
_PyCFrame* cframe;
#endif
} PyGreenlet;

Expand Down
18 changes: 18 additions & 0 deletions docs/changes/1867.feature
@@ -0,0 +1,18 @@
Added preliminary support for Python 3.11 (rc2 and later).

Some platforms may or may not have binary wheels at this time.

.. important:: Support for legacy versions of Python, including 2.7
and 3.6, will be ending soon. The
maintenance burden has become too great and the
maintainer's time is too limited.

Ideally, there will be a release of gevent compatible
with a final release of greenlet 2.0 that still
supports those legacy versions, but that may not be
possible; this may be the final release to support them.

:class:`gevent.threadpool.ThreadPool` can now optionally expire idle
threads. This is used by default in the implicit thread pool used for
DNS requests and other user-submitted tasks; other uses of a
thread-pool need to opt-in to this.
5 changes: 3 additions & 2 deletions pyproject.toml
Expand Up @@ -22,13 +22,14 @@ requires = [
# This was fixed in 3.0a5 (https://github.com/cython/cython/issues/3578)
# 3.0a6 fixes an issue cythonizing source on 32-bit platforms.
# 3.0a9 is needed for Python 3.10.
"Cython >= 3.0a9",
"Cython >= 3.0a11",
# See version requirements in setup.py
"cffi >= 1.12.3 ; platform_python_implementation == 'CPython'",
# Python 3.7 requires at least 0.4.14, which is ABI incompatible with earlier
# releases. Python 3.9 and 3.10 require 0.4.16;
# 0.4.17 is ABI incompatible with earlier releases, but compatible with 1.0
"greenlet >= 0.4.17, < 2.0 ; platform_python_implementation == 'CPython'",
# 1.1.3 is needed for CPython 3.11
"greenlet >= 1.1.3, < 2.0 ; platform_python_implementation == 'CPython'",
]

[tool.towncrier]
Expand Down
4 changes: 3 additions & 1 deletion setup.py
Expand Up @@ -201,7 +201,8 @@
# the release of 1.0a1 it began promising ABI stability with SemVer
# so we can add an upper bound).
# 1.1.0 is required for 3.10; it has a new ABI, but only on 1.1.0.
'greenlet >= 1.1.0, < 2.0; platform_python_implementation=="CPython"',
# 1.1.3 is needed for 3.11, and supports everything 1.1.0 did.
'greenlet >= 1.1.3, < 2.0; platform_python_implementation=="CPython"',
]

# Note that we don't add cffi to install_requires, it's
Expand Down Expand Up @@ -449,6 +450,7 @@ def run_setup(ext_modules):
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Operating System :: MacOS :: MacOS X",
Expand Down
95 changes: 95 additions & 0 deletions src/gevent/_compat.h
@@ -0,0 +1,95 @@
#ifndef _COMPAT_H
#define _COMPAT_H

/**
* Compatibility helpers for things that are better handled at C
* compilation time rather than Cython code generation time.
*/

#include <Python.h>

#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if PY_VERSION_HEX >= 0x30B00A6
# define GEVENT_PY311 1
#else
# define GEVENT_PY311 0
# define _PyCFrame CFrame
#endif

/* FrameType and CodeType changed a lot in 3.11. */
#if GREENLET_PY311
/* _PyInterpreterFrame moved to the internal C API in Python 3.11 */
# include <internal/pycore_frame.h>
#else
#include <frameobject.h>
#if PY_MAJOR_VERSION < 3 || (PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION < 9)
/* these were added in 3.9, though they officially became stable in 3.10 */
/* the official versions of these functions return strong references, so we
need to increment the refcount before returning, not just to match the
official functions, but to match what Cython expects an API like this to
return. Otherwise we get crashes. */
static PyObject* PyFrame_GetBack(PyFrameObject* frame)
{
PyObject* result = (PyObject*)((PyFrameObject*)frame)->f_back;
Py_XINCREF(result);
return result;
}

static PyObject* PyFrame_GetCode(PyFrameObject* frame)
{
PyObject* result = (PyObject*)((PyFrameObject*)frame)->f_code;
/* There is always code! */
Py_INCREF(result);
return result;
}
#endif /* support 3.8 and below. */
#endif

/**
Unlike PyFrame_GetBack, which can return NULL,
this method is guaranteed to return a new reference to an object.
The object is either a frame object or None.
This is necessary to help Cython deal correctly with reference counting.
(There are other ways of dealing with this having to do with exactly how
variables/return types are declared IIRC, but this is the most
straightforward. Still, it is critical that the cython declaration of
this function use ``object`` as its return type.)
*/
static PyObject* Gevent_PyFrame_GetBack(PyObject* frame)
{
PyObject* back = (PyObject*)PyFrame_GetBack((PyFrameObject*)frame);
if (back) {
return back;
}
Py_RETURN_NONE;
}

/* These are just for typing purposes to appease the compiler. */

static int Gevent_PyFrame_GetLineNumber(PyObject* o)
{
return PyFrame_GetLineNumber((PyFrameObject*)o);
}

static PyObject* Gevent_PyFrame_GetCode(PyObject* o)
{
return (PyObject*)PyFrame_GetCode((PyFrameObject*)o);
}

#ifdef __cplusplus
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif
#endif /* _COMPAT_H */
1 change: 1 addition & 0 deletions src/gevent/_compat.py
Expand Up @@ -19,6 +19,7 @@
PY37 = sys.version_info[:2] >= (3, 7)
PY38 = sys.version_info[:2] >= (3, 8)
PY39 = sys.version_info[:2] >= (3, 9)
PY311 = sys.version_info[:2] >= (3, 11)
PYPY = hasattr(sys, 'pypy_version_info')
WIN = sys.platform.startswith("win")
LINUX = sys.platform.startswith('linux')
Expand Down
37 changes: 36 additions & 1 deletion src/gevent/_config.py
Expand Up @@ -6,6 +6,11 @@
is an object of :class:`Config`.
.. versionadded:: 1.3a2
.. versionchanged:: NEXT
Invoking this module like ``python -m gevent._config`` will
print a help message about available configuration properties.
This is handy to quickly look for environment variables.
"""

from __future__ import print_function, absolute_import, division
Expand Down Expand Up @@ -206,6 +211,12 @@ def set(self, name, value):
def __dir__(self):
return list(self.settings)

def print_help(self):
for k, v in self.settings.items():
print(k)
print(textwrap.indent(v.__doc__.lstrip(), ' ' * 4))
print()


class ImportableSetting(object):

Expand Down Expand Up @@ -340,6 +351,24 @@ class Threadpool(ImportableSetting, Setting):

default = 'gevent.threadpool.ThreadPool'

class ThreadpoolIdleTaskTimeout(FloatSettingMixin, Setting):
document = True
name = 'threadpool_idle_task_timeout'
environment_key = 'GEVENT_THREADPOOL_IDLE_TASK_TIMEOUT'

desc = """\
How long threads in the default threadpool (used for
DNS by default) are allowed to be idle before exiting.
Use -1 for no timeout.
.. versionadded:: NEXT
"""

# This value is picked pretty much arbitrarily.
# We want to balance performance (keeping threads around)
# with memory/cpu usage (letting threads go).
default = 5.0

class Loop(ImportableSetting, Setting):

Expand Down Expand Up @@ -455,7 +484,9 @@ class TrackGreenletTree(BoolSettingMixin, Setting):
Setting this to a false value will make spawning `Greenlet`
objects and using `spawn_raw` faster, but the
``spawning_greenlet``, ``spawn_tree_locals`` and ``spawning_stack``
will not be captured.
will not be captured. Setting this to a false value can also
reduce memory usage because capturing the stack captures
some information about Python frames.
.. versionadded:: 1.3b1
"""
Expand Down Expand Up @@ -699,3 +730,7 @@ def kwarg_name(self):
Loop().get()
except ImportError: # pragma: no cover
pass


if __name__ == '__main__':
config.print_help()

0 comments on commit 65417fe

Please sign in to comment.