Skip to content

Commit

Permalink
Merge pull request #1809 from gevent/support-3.10
Browse files Browse the repository at this point in the history
Support 3.10 now that the ABI is officially stable with 3.10rc1
  • Loading branch information
jamadden committed Aug 5, 2021
2 parents f6658dd + 189def7 commit d877dce
Show file tree
Hide file tree
Showing 86 changed files with 13,598 additions and 5,312 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: [2.7, pypy-2.7, pypy-3.6, 3.6, 3.7, 3.8, 3.9]
python-version: [2.7, pypy-2.7, pypy-3.6, 3.6, 3.7, 3.8, 3.9, '3.10.0-rc.1']
# ubuntu-latest is at least 20.04. But this breaks the SSL
# tests because Ubuntu increased the default OpenSSL
# strictness.
Expand Down Expand Up @@ -173,6 +173,8 @@ jobs:
python-version: 3.8
- os: ubuntu-18.04
python-version: 3.9
- os: ubuntu-18.04
python-version: '3.10.0-rc.1'
steps:
- name: checkout
uses: actions/checkout@v2
Expand Down Expand Up @@ -255,7 +257,7 @@ jobs:
pip install -U -q setuptools wheel twine
pip install -q -U 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"'
pip install -q -U 'cffi;platform_python_implementation=="CPython"'
pip install -q -U 'cython>=3.0a5'
pip install -q -U 'cython>=3.0a9'
pip install 'greenlet>=1.0a1;platform_python_implementation=="CPython"'
- name: Build gevent
Expand Down
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ Features
Reported by Suhail Muhammed.
See :issue:`1678`.

- Drop support for Python 3.5.

Bugfixes
--------
Expand Down
6 changes: 6 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ environment:
# a later point release.

# 64-bit
- PYTHON: "C:\\Python310-x64"
PYTHON_VERSION: "3.10.0rc1"
PYTHON_ARCH: "64"
PYTHON_EXE: python
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019


- PYTHON: "C:\\Python39-x64"
PYTHON_VERSION: "3.9.x"
Expand Down
3 changes: 3 additions & 0 deletions deps/greenlet/greenlet.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ typedef struct _greenlet {
#if PY_VERSION_HEX >= 0x030700A3
PyObject* context;
#endif
#if PY_VERSION_HEX >= 0x30A00B1
CFrame* cframe;
#endif
} PyGreenlet;

#define PyGreenlet_Check(op) PyObject_TypeCheck(op, &PyGreenlet_Type)
Expand Down
2 changes: 1 addition & 1 deletion docs/changes/1758.feature
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Update the embedded c-ares from 1.16.1 to 1.17.1.`
Update the embedded c-ares from 1.16.1 to 1.17.1.
7 changes: 7 additions & 0 deletions docs/changes/1790.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Add support for Python 3.10rc1 and newer.

As part of this, the minimum required greenlet version was increased
to 1.1.0 (on CPython), and the minimum version of Cython needed to
build gevent from a source checkout is 3.0a9.

Note that the dnspython resolver is not available on Python 3.10.
2 changes: 1 addition & 1 deletion docs/changes/1801.feature
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Update from Cython 3.0a6 to 3.0a8.
Update from Cython 3.0a6 to 3.0a9.
14 changes: 10 additions & 4 deletions docs/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
Supported Platforms
===================

This version of gevent runs on Python 2.7.9 and up, and Python 3.5, 3.6, 3.7 and
3.8. gevent requires the `greenlet <https://greenlet.readthedocs.io>`_
This version of gevent runs on Python 2.7.9 and up, and many versions
of Python 3 (for exact details, see the classifiers on the PyPI page
or in ``setup.py``). gevent requires the `greenlet <https://greenlet.readthedocs.io>`_
library and will install the `cffi`_ library by default on Windows.
The cffi library will become the default on all platforms in a future
release of gevent.
Expand Down Expand Up @@ -70,7 +71,10 @@ supported.
| | |
| | |
+-------+-------+

|3.5.x | 20.9.0|
| | |
| | |
+-------+-------+

Installation
============
Expand Down Expand Up @@ -144,11 +148,13 @@ events
will be removed in gevent 21.0.

dnspython
Enables the new pure-Python resolver, backed by `dnspython
Enables a pure-Python resolver, backed by `dnspython
<https://pypi.org/project/dnspython>`_. On Python 2, this also
includes `idna <https://pypi.org/project/idna>`_. They can be
installed with the ``dnspython`` extra.

.. note:: This is not compatible with Python 3.10 or dnspython 2.

monitor
Enhancements to gevent's self-monitoring capabilities. This
includes the `psutil <https://pypi.org/project/psutil>`_ library
Expand Down
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ requires = [
# but once that was fixed, 3.0a4 led to all of our leak tests
# failing in Python 2 (https://travis-ci.org/github/gevent/gevent/jobs/683782800);
# This was fixed in 3.0a5 (https://github.com/cython/cython/issues/3578)
# 3.0a6 fixes an issue cythonizing source on 32-bit platforms
"Cython >= 3.0a8",
# 3.0a6 fixes an issue cythonizing source on 32-bit platforms.
# 3.0a9 is needed for Python 3.10.
"Cython >= 3.0a9",
# 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
Expand Down
16 changes: 9 additions & 7 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,9 @@
# Binary compatibility would break if the greenlet struct changes.
# (Which it did in 0.4.14 for Python 3.7 and again in 0.4.17; with
# the release of 1.0a1 it began promising ABI stability with SemVer
# so we can add an upper bound)
'greenlet >= 0.4.17, < 2.0; platform_python_implementation=="CPython"',
# 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"',
]

# Note that we don't add cffi to install_requires, it's
Expand Down Expand Up @@ -298,8 +299,10 @@
## Extras

EXTRA_DNSPYTHON = [
'dnspython >= 1.16.0, < 2.0',
'idna',
# We're not currently compatible with 2.0, and dnspython 1.x isn't
# compatible weth Python 3.10 because of the removal of ``collections.MutableMapping``.
'dnspython >= 1.16.0, < 2.0; python_version < "3.10"',
'idna; python_version < "3.10"',
]
EXTRA_EVENTS = [
# No longer does anything, but the extra must stay around
Expand Down Expand Up @@ -441,12 +444,11 @@ def run_setup(ext_modules):
classifiers=[
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Operating System :: MacOS :: MacOS X",
Expand All @@ -457,7 +459,7 @@ def run_setup(ext_modules):
"Intended Audience :: Developers",
"Development Status :: 4 - Beta"
],
python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*",
python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5",
entry_points={
'gevent.plugins.monkey.will_patch_all': [
"signal_os_incompat = gevent.monkey:_subscribe_signal_os",
Expand Down
17 changes: 13 additions & 4 deletions src/gevent/_socket3.py
Original file line number Diff line number Diff line change
Expand Up @@ -604,8 +604,17 @@ def socketpair(family=AF_INET, type=SOCK_STREAM, proto=0):
return (ssock, csock)


if hasattr(__socket__, 'close'): # Python 3.7b1+
close = __socket__.close # pylint:disable=no-member
__imports__ += ['close']

__all__ = __implements__ + __extensions__ + __imports__
__version_specific__ = (
# Python 3.7b1+
'close',
# Python 3.10rc1+
'TCP_KEEPALIVE',
'TCP_KEEPCNT',
)
for _x in __version_specific__:
if hasattr(__socket__, _x):
vars()[_x] = getattr(__socket__, _x)
if _x not in __all__:
__all__.append(_x)
del _x
23 changes: 17 additions & 6 deletions src/gevent/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,16 +581,22 @@ def __new__(cls, *args, **kw):
self.__cinit__(*args[1:], **kw)
return self

try:
if local.__module__ == 'gevent.local':
# PyPy2/3 and CPython handle adding a __new__ to the class
# in different ways. In CPython and PyPy3, it must be wrapped with classmethod;
# in PyPy2 < 7.3.3, it must not. In either case, the args that get passed to
# it are stil wrong.
local.__new__ = 'None'
except TypeError: # pragma: no cover
# Must be compiled
pass
else:
#
# Prior to Python 3.10, Cython-compiled classes were immutable and
# raised a TypeError on assignment to __new__, and we relied on that
# to detect the compiled version; but that breaks in
# 3.10 as classes are now mutable. (See
# https://github.com/cython/cython/issues/4326).
#
# That's OK; post https://github.com/gevent/gevent/issues/1480, the Cython-compiled
# module has a different name than the pure-Python version and we can check for that.
# It's not as direct, but it works.
# So here we're not compiled
from gevent._compat import PYPY
from gevent._compat import PY2
if PYPY and PY2:
Expand All @@ -606,6 +612,11 @@ def __new__(cls, *args, **kw):

del PYPY
del PY2
else: # pragma: no cover
# Make sure we revisit in case of changes to the (accelerator) module names.
if local.__module__ != 'gevent._gevent_clocal':
raise AssertionError("Module names changed (local: %r; __name__: %r); revisit this code" % (
local.__module__, __name__) )

_init()

Expand Down
9 changes: 9 additions & 0 deletions src/gevent/monkey.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
Patching too late can lead to unreliable behaviour (for example, some
modules may still use blocking sockets) or even errors.
.. tip::
Be sure to read the documentation for each patch function to check for
known incompatibilities.
Querying
========
Expand Down Expand Up @@ -713,6 +718,10 @@ def patch_thread(threading=True, _threading_local=True, Event=True, logging=True
:class:`concurrent.futures.ProcessPoolExecutor` (which uses a
``Queue``) will hang the process.
Monkey-patching with this function and using
sub-interpreters (and advanced C-level API) and threads may be
unstable on certain platforms.
.. versionchanged:: 1.1b1
Add *logging* and *existing_locks* params.
.. versionchanged:: 1.3a2
Expand Down
2 changes: 2 additions & 0 deletions src/gevent/testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
from .sysinfo import RESOLVER_NOT_SYSTEM
from .sysinfo import RESOLVER_DNSPYTHON
from .sysinfo import RESOLVER_ARES
from .sysinfo import resolver_dnspython_available

from .sysinfo import EXPECT_POOR_TIMER_RESOLUTION

Expand All @@ -107,6 +108,7 @@
from .skipping import skipWithCExtensions
from .skipping import skipOnLibuvOnTravisOnCPython27
from .skipping import skipOnPy37
from .skipping import skipOnPy310
from .skipping import skipOnPy3
from .skipping import skipWithoutResource
from .skipping import skipWithoutExternalNetwork
Expand Down
22 changes: 22 additions & 0 deletions src/gevent/testing/patched_tests_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from .sysinfo import PY37
from .sysinfo import PY38
from .sysinfo import PY39
from .sysinfo import PY310

from .sysinfo import WIN
from .sysinfo import OSX
Expand Down Expand Up @@ -1373,6 +1374,27 @@ def test(*args, **kwargs):
'test_ftplib.TestTLS_FTPClassMixin.test_retrlines_too_long',
]

if PY310:
disabled_tests += [
# They arbitrarily made some types so that they can't be created;
# that's an implementation detail we're not going to follow (
# it would require them to be factory functions).
'test_select.SelectTestCase.test_disallow_instantiation',
'test_threading.ThreadTests.test_disallow_instantiation',
# This wants two true threads to work, but a CPU bound loop
# in a greenlet can't be interrupted.
'test_threading.InterruptMainTests.test_can_interrupt_tight_loops',
]

if TRAVIS:
disabled_tests += [
# The mixing of subinterpreters (with threads) and gevent apparently
# leads to a segfault on Ubuntu/GitHubActions/3.10rc1. Not clear why.
# But that's not a great use case for gevent.
'test_threading.SubinterpThreadingTests.test_threads_join',
'test_threading.SubinterpThreadingTests.test_threads_join_2',
]

if TRAVIS:
disabled_tests += [
# These tests frequently break when we try to use newer Travis CI images,
Expand Down
1 change: 1 addition & 0 deletions src/gevent/testing/skipping.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def _do_not_skip(reason):
skipOnPy2 = unittest.skip if sysinfo.PY2 else _do_not_skip
skipOnPy3 = unittest.skip if sysinfo.PY3 else _do_not_skip
skipOnPy37 = unittest.skip if sysinfo.PY37 else _do_not_skip
skipOnPy310 = unittest.skip if sysinfo.PY310 else _do_not_skip

skipOnPurePython = unittest.skip if sysinfo.PURE_PYTHON else _do_not_skip
skipWithCExtensions = unittest.skip if not sysinfo.PURE_PYTHON else _do_not_skip
Expand Down
16 changes: 15 additions & 1 deletion src/gevent/testing/sysinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
PY37 = None
PY38 = None
PY39 = None
PY310 = None

NON_APPLICABLE_SUFFIXES = ()
if sys.version_info[0] >= 3:
Expand All @@ -83,6 +84,8 @@
PY38 = True
if sys.version_info[1] >= 9:
PY39 = True
if sys.version_info[1] >= 10:
PY310 = True

elif sys.version_info[0] == 2:
# Any python 2
Expand Down Expand Up @@ -158,13 +161,15 @@ def _make_socket_errnos(*names):
def get_python_version():
"""
Return a string of the simple python version,
such as '3.8.0b4'. Handles alpha and beta and final releases.
such as '3.8.0b4'. Handles alpha, beta, release candidate, and final releases.
"""
version = '%s.%s.%s' % sys.version_info[:3]
if sys.version_info[3] == 'alpha':
version += 'a%s' % sys.version_info[4]
elif sys.version_info[3] == 'beta':
version += 'b%s' % sys.version_info[4]
elif sys.version_info[3] == 'candidate':
version += 'rc%s' % sys.version_info[4]

return version

Expand All @@ -188,3 +193,12 @@ def libev_supports_linux_iouring():
from platform import release

return system() == 'Linux' and LooseVersion(release() or '0') >= LooseVersion('5.3')

def resolver_dnspython_available():
# Try hard not to leave around junk we don't have to.
import pkg_resources
try:
pkg_resources.get_distribution('dnspython')
except pkg_resources.DistributionNotFound:
return False
return True
4 changes: 2 additions & 2 deletions src/gevent/testing/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ def start(command, quiet=False, **kwargs):
if timeout is not None:
t = get_original('threading', 'Timer')(timeout, kill, args=(popen, ))
popen.timer = t
t.setDaemon(True)
t.daemon = True
t.start()
popen.timer = t
return popen
Expand Down Expand Up @@ -631,7 +631,7 @@ class alarm(threading.Thread):

def __init__(self, timeout):
threading.Thread.__init__(self)
self.setDaemon(True)
self.daemon = True
self.timeout = timeout
self.start()

Expand Down

0 comments on commit d877dce

Please sign in to comment.