Commit 5dfe00d6 authored by Jason Madden's avatar Jason Madden

Get the basic tests passing on 3.11; add it to the CI matrix to see what we see there.

Haven't tried any of the 3.11-specific tests yet.
parent 6d938e37
......@@ -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.
......@@ -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-rc.2'
steps:
- name: checkout
uses: actions/checkout@v2
......
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.
......@@ -19,6 +19,7 @@ PY36 = sys.version_info[:2] >= (3, 6)
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')
......
......@@ -375,7 +375,7 @@ class Greenlet(greenlet):
@property
def loop(self):
# needed by killall
hub = get_my_hub(self) # type:SwitchOutGreenletWithLoop pylint:disable=undefined-variable
hub = get_my_hub(self) # pylint:disable=undefined-variable
return hub.loop
def __nonzero__(self):
......@@ -619,7 +619,7 @@ class Greenlet(greenlet):
"""Schedule the greenlet to run in this loop iteration"""
if self._start_event is None:
_call_spawn_callbacks(self)
hub = get_my_hub(self) # type:SwitchOutGreenletWithLoop pylint:disable=undefined-variable
hub = get_my_hub(self) # pylint:disable=undefined-variable
self._start_event = hub.loop.run_callback(self.switch)
def start_later(self, seconds):
......@@ -1151,7 +1151,7 @@ def killall(greenlets, exception=GreenletExit, block=True, timeout=None):
Now accepts raw greenlets created by :func:`gevent.spawn_raw`.
"""
need_killed = [] # type: list
need_killed = []
for glet in greenlets:
# Quick pass through to prevent any greenlet from
# actually being switched to if it hasn't already.
......
......@@ -14,6 +14,7 @@ as well as the constants from the :mod:`socket` module are imported into this mo
# pylint: disable=undefined-variable
from gevent._compat import PY3
from gevent._compat import PY311
from gevent._compat import exc_clear
from gevent._util import copy_globals
......@@ -59,9 +60,9 @@ except AttributeError:
_GLOBAL_DEFAULT_TIMEOUT = object()
def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None):
def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None, **kwargs):
"""
create_connection(address, timeout=None, source_address=None) -> socket
create_connection(address, timeout=None, source_address=None, *, all_errors=False) -> socket
Connect to *address* and return the :class:`gevent.socket.socket`
object.
......@@ -80,9 +81,18 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=N
If the host part of the address includes an IPv6 scope ID,
it will be used instead of ignored, if the platform supplies
:func:`socket.inet_pton`.
.. versionchanged:: NEXT
Add the *all_errors* argument. This only has meaning on Python 3.11;
it is a programming error to pass it on earlier versions.
"""
all_errors = False
if PY311:
all_errors = kwargs.pop('all_errors', False)
if kwargs:
raise TypeError("Too many keyword arguments to create_connection", kwargs)
host, port = address
exceptions = []
# getaddrinfo is documented as returning a list, but our interface
# is pluggable, so be sure it does.
addrs = list(getaddrinfo(host, port, 0, SOCK_STREAM))
......@@ -99,12 +109,25 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=N
if source_address:
sock.bind(source_address)
sock.connect(sa)
except error:
except error as exc:
if not all_errors:
exceptions = [exc] # raise only the last error
else:
exceptions.append(exc)
del exc # cycle
if sock is not None:
sock.close()
sock = None
if res is addrs[-1]:
raise
if not all_errors:
del exceptions[:]
raise
try:
raise ExceptionGroup("create_connection failed", exceptions)
finally:
# Break explicitly a reference cycle
del exceptions[:]
# without exc_clear(), if connect() fails once, the socket
# is referenced by the frame in exc_info and the next
# bind() fails (see test__socket.TestCreateConnection)
......@@ -122,6 +145,8 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=N
sock = None
raise
else:
# break reference cycles
del exceptions[:]
try:
return sock
finally:
......
......@@ -431,9 +431,12 @@ class TestCase(TestCaseMetaClass("NewBase",
if hasattr(sig, 'keywords'): # the old version
self.assertEqual(sig.keywords, gevent_sig.keywords, func_name)
else:
# The new hotness
self.assertEqual(sig.kwonlyargs, gevent_sig.kwonlyargs)
self.assertEqual(sig.kwonlydefaults, gevent_sig.kwonlydefaults)
# The new hotness. Unfortunately, we can't actually check these things
# until we drop Python 2 support from the shared code. The only known place
# this is a problem is python 3.11 socket.create_connection(), which we manually
# ignore. So the checks all pass as is.
self.assertEqual(sig.kwonlyargs, gevent_sig.kwonlyargs, func_name)
self.assertEqual(sig.kwonlydefaults, gevent_sig.kwonlydefaults, func_name)
# Should deal with others: https://docs.python.org/3/library/inspect.html#inspect.getfullargspec
def assertEqualFlakyRaceCondition(self, a, b):
......
......@@ -581,6 +581,10 @@ class TestFunctions(greentest.TestCase):
exclude.append('gethostbyname')
exclude.append('gethostbyname_ex')
exclude.append('gethostbyaddr')
if sys.version_info[:2] == (3, 11):
# Be careful not to exclude this on 3.12, etc, in case of
# more changes.
exclude.append('create_connection')
self.assertMonkeyPatchedFuncSignatures('socket', exclude=exclude)
def test_resolve_ipv6_scope_id(self):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment