Commit 10c84561 authored by Jason Madden's avatar Jason Madden

Basic tests for 3.12 pass locally.

parent 748cedaf
......@@ -8,3 +8,6 @@ Related changes include:
- Honor ``sys.unraisablehook`` when a callback function produces an
exception, and handling the exception in the hub *also* produces an
exception. In older versions, these would be simply printed.
- ``setup.py`` no longer includes the ``setup_requires`` keyword.
Installation with a tool that understands ``pyproject.toml`` is
recommended.
......@@ -37,7 +37,10 @@ requires = [
# 1.1.3 is needed for CPython 3.11.
# 2.0 is not ABI compatible with earlier releases, but with luck it won't
# have to break the ABI again.
"greenlet >= 2.0.0 ; platform_python_implementation == 'CPython'",
# 3.0 is ABI compatible with earlier releases, so we can switch back and
# forth between 2 and 3 without recompiling. 3.0 is required for
# Python 3.12
"greenlet >= 3.0a1 ; platform_python_implementation == 'CPython'",
]
[tool.towncrier]
......
......@@ -208,7 +208,10 @@ greenlet_requires = [
# 1.1.3 is needed for 3.11, and supports everything 1.1.0 did.
# 2.0.0 supports everything 1.1.3 did, but breaks the ABI in a way that hopefully
# won't break again.
'greenlet >= 2.0.0 ; platform_python_implementation=="CPython"',
# 3.0 is ABI compatible and adds support for Python 3.12 (but right
# now it's alpha because of Cython, so we only require it on 3.12)
'greenlet >= 2.0.0 ; platform_python_implementation=="CPython" and python_version < "3.12"',
'greenlet >= 3.0a1 ; platform_python_implementation=="CPython" and python_version >= "3.12"',
]
# Note that we don't add cffi to install_requires, it's
......@@ -235,19 +238,6 @@ install_requires = greenlet_requires + CFFI_REQUIRES + [
'zope.interface',
]
# We use headers from greenlet, so it needs to be installed before we
# can compile. If it isn't already installed before we start
# installing, and we say 'pip install gevent', a 'setup_requires'
# doesn't save us: pip happily downloads greenlet and drops it in a
# .eggs/ directory in the build directory, but that directory doesn't
# have includes! So we fail to build a wheel, pip goes ahead and
# installs greenlet, and builds gevent again, which works.
# Since we ship the greenlet header for buildout support (which fails
# to install the headers at all, AFAICS, we don't need to bother with
# the buggy setup_requires.)
setup_requires = CFFI_REQUIRES + []
if PYPY:
# These use greenlet/greenlet.h, which doesn't exist on PyPy
......@@ -397,7 +387,6 @@ def run_setup(ext_modules):
'clean': GeventClean,
},
install_requires=install_requires,
setup_requires=setup_requires,
extras_require={
# Each extra intended for end users must be documented in install.rst
'dnspython': EXTRA_DNSPYTHON,
......@@ -422,7 +411,6 @@ def run_setup(ext_modules):
# anyway (coveralls -> cryptopgraphy -> openssl).
# coverage 5 needs coveralls 1.11
'coverage >= 5.0 ; sys_platform != "win32"',
'coveralls>=1.7.0 ; sys_platform != "win32"',
# leak checks. previously we had a hand-rolled version.
'objgraph',
......
This diff is collapsed.
......@@ -59,7 +59,8 @@ except AttributeError:
_GLOBAL_DEFAULT_TIMEOUT = object()
def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None, **kwargs):
def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None, *,
all_errors=False):
"""
create_connection(address, timeout=None, source_address=None, *, all_errors=False) -> socket
......@@ -81,20 +82,18 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=N
it will be used instead of ignored, if the platform supplies
:func:`socket.inet_pton`.
.. versionchanged:: 22.08.0
Add the *all_errors* argument. This only has meaning on Python 3.11;
Add the *all_errors* argument. This only has meaning on Python 3.11+;
it is a programming error to pass it on earlier versions.
.. versionchanged:: NEXT
You can pass a value for ``all_errors`` on any version of Python.
It is forced to false for any version before 3.11 inside the function.
"""
# Sigh. This function is a near-copy of the CPython implementation.
# Even though we simplified some things, it's still a little complex to
# cope with error handling, which got even more complicated in 3.11.
# pylint:disable=too-many-locals,too-many-branches
all_errors = False
if PY311:
all_errors = kwargs.pop('all_errors', False)
if kwargs:
raise TypeError("Too many keyword arguments to create_connection", kwargs)
if not PY311:
all_errors = False
host, port = address
exceptions = []
......
This diff is collapsed.
......@@ -121,8 +121,6 @@ class TestConfig(unittest.TestCase):
class TestImportableSetting(unittest.TestCase):
assertRaisesRegex = getattr(unittest.TestCase, 'assertRaisesRegex',
unittest.TestCase.assertRaisesRegexp)
def test_empty_list(self):
i = _config.ImportableSetting()
with self.assertRaisesRegex(ImportError,
......
......@@ -21,9 +21,6 @@ class Test(unittest.TestCase):
# NOTE that we extend unittest.TestCase, not greentest.TestCase
# Extending the later causes the wrong hub to get used.
assertRaisesRegex = getattr(unittest.TestCase, 'assertRaisesRegex',
getattr(unittest.TestCase, 'assertRaisesRegexp'))
BACKENDS_THAT_SUCCEED_WHEN_FD_CLOSED = (
'kqueue',
'epoll',
......
......@@ -62,7 +62,8 @@ class Test_wsgiserver(util.TestServer):
sock = socket.create_connection((params.DEFAULT_LOCAL_HOST_ADDR, self.PORT))
ssl_sock = None
if self._use_ssl:
ssl_sock = ssl.wrap_socket(sock) # pylint:disable=deprecated-method
context = ssl.SSLContext()
ssl_sock = context.wrap_socket(sock)
sock_file = ssl_sock.makefile(mode='rwb')
else:
sock_file = sock.makefile(mode='rwb')
......
......@@ -14,7 +14,7 @@ from gevent.testing.params import DEFAULT_CONNECT
from gevent.testing.sockets import tcp_listener
dirname = os.path.dirname(os.path.abspath(__file__))
certfile = os.path.join(dirname, '2_7_keycert.pem')
CERTFILE = os.path.join(dirname, '2_7_keycert.pem')
pid = os.getpid()
PY3 = greentest.PY3
......@@ -259,7 +259,7 @@ class TestSSL(Test):
try:
# Note: We get ResourceWarning about 'x'
# on Python 3 if we don't join the spawned thread
x = ssl.wrap_socket(connector)
x = ssl.SSLContext().wrap_socket(connector)
# Wait to be fully accepted. We could otherwise raise ahead
# of the server and close ourself before it's ready to read.
accepted_event.wait()
......@@ -284,7 +284,7 @@ class TestSSL(Test):
with Closing() as closer:
s = closer(self.make_open_socket())
fileno = s.fileno()
s = closer(ssl.wrap_socket(s))
s = closer(ssl.SSLContext().wrap_socket(s))
fileno = s.fileno()
self.assert_open(s, fileno)
s.close()
......@@ -293,7 +293,7 @@ class TestSSL(Test):
def test_makefile1(self):
with Closing() as closer:
raw_s = closer(self.make_open_socket())
s = closer(ssl.wrap_socket(raw_s))
s = closer(ssl.SSLContext().wrap_socket(raw_s))
fileno = s.fileno()
self.assert_open(s, fileno)
......@@ -310,7 +310,7 @@ class TestSSL(Test):
s = closer(self.make_open_socket())
fileno = s.fileno()
s = closer(ssl.wrap_socket(s))
s = closer(ssl.SSLContext().wrap_socket(s))
fileno = s.fileno()
self.assert_open(s, fileno)
f = closer(s.makefile())
......@@ -321,6 +321,11 @@ class TestSSL(Test):
s.close()
self.assert_closed(s, fileno)
def _wrap_socket(self, sock, *, keyfile, certfile, server_side=False):
context = ssl.SSLContext()
context.load_cert_chain(certfile=certfile, keyfile=keyfile)
return context.wrap_socket(sock, server_side=server_side)
def test_server_simple(self):
with Closing() as closer:
listener = closer(tcp_listener(backlog=1))
......@@ -334,8 +339,8 @@ class TestSSL(Test):
client_socket = closer.accept(listener)
t.accepted_event.set()
client_socket = closer(
ssl.wrap_socket(client_socket, keyfile=certfile, certfile=certfile,
server_side=True))
self._wrap_socket(client_socket, keyfile=CERTFILE, certfile=CERTFILE,
server_side=True))
fileno = client_socket.fileno()
self.assert_open(client_socket, fileno)
client_socket.close()
......@@ -354,8 +359,8 @@ class TestSSL(Test):
client_socket = closer.accept(listener)
t.accepted_event.set()
client_socket = closer(
ssl.wrap_socket(client_socket, keyfile=certfile, certfile=certfile,
server_side=True))
self._wrap_socket(client_socket, keyfile=CERTFILE, certfile=CERTFILE,
server_side=True))
fileno = client_socket.fileno()
self.assert_open(client_socket, fileno)
f = client_socket.makefile()
......@@ -377,8 +382,8 @@ class TestSSL(Test):
t.accepted_event.set()
client_socket = closer.accept(listener)
client_socket = closer(
ssl.wrap_socket(client_socket, keyfile=certfile, certfile=certfile,
server_side=True))
self._wrap_socket(client_socket, keyfile=CERTFILE, certfile=CERTFILE,
server_side=True))
fileno = client_socket.fileno()
self.assert_open(client_socket, fileno)
......@@ -394,7 +399,7 @@ class TestSSL(Test):
raw_listener = tcp_listener(backlog=1)
fileno = raw_listener.fileno()
port = raw_listener.getsockname()[1]
listener = ssl.wrap_socket(raw_listener, keyfile=certfile, certfile=certfile)
listener = self._wrap_socket(raw_listener, keyfile=CERTFILE, certfile=CERTFILE)
connector = socket.socket()
t = self._make_ssl_connect_task(connector, port)
......@@ -414,13 +419,13 @@ class TestSSL(Test):
def test_serverssl_makefile2(self):
raw_listener = tcp_listener(backlog=1)
port = raw_listener.getsockname()[1]
listener = ssl.wrap_socket(raw_listener, keyfile=certfile, certfile=certfile)
listener = self._wrap_socket(raw_listener, keyfile=CERTFILE, certfile=CERTFILE)
accepted_event = threading.Event()
def connect(connector=socket.socket()):
try:
connector.connect((DEFAULT_CONNECT, port))
s = ssl.wrap_socket(connector)
s = ssl.SSLContext().wrap_socket(connector)
accepted_event.wait()
s.sendall(b'test_serverssl_makefile2')
s.shutdown(socket.SHUT_RDWR)
......
......@@ -581,9 +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.
if sys.version_info[:2] < (3, 11):
# 3.11+ add ``*, all_errors=False``. We allow that on all versions,
# forcing it to a false value if the user sends a true value before
# exception groups exist.
exclude.append('create_connection')
self.assertMonkeyPatchedFuncSignatures('socket', exclude=exclude)
......
......@@ -10,15 +10,25 @@ import gevent.testing as greentest
from gevent.tests import test__socket
import ssl
from gevent.testing import PY2
def ssl_listener(private_key, certificate):
raw_listener = socket.socket()
greentest.bind_and_listen(raw_listener)
# pylint:disable=deprecated-method
sock = ssl.wrap_socket(raw_listener, private_key, certificate, server_side=True)
sock = wrap_socket(raw_listener, keyfile=private_key, certfile=certificate,
server_side=True)
return sock, raw_listener
def wrap_socket(sock, *, keyfile=None, certfile=None, server_side=False):
context = ssl.SSLContext(
protocol=ssl.PROTOCOL_TLS
)
context.verify_mode = ssl.CERT_NONE
context.check_hostname = False
context.load_default_certs()
if keyfile is not None or certfile is not None:
context.load_cert_chain(certfile=certfile, keyfile=keyfile)
return context.wrap_socket(sock, server_side=server_side)
class TestSSL(test__socket.TestTCP):
......@@ -34,7 +44,7 @@ class TestSSL(test__socket.TestTCP):
# PyPy3 7.2 has a bug, though: it shares much of the SSL implementation with Python 2,
# and it unconditionally does `socket.sslerror = SSLError` when ssl is imported.
# So we can't rely on getattr/hasattr tests, we must be explicit.
TIMEOUT_ERROR = socket.sslerror if PY2 else socket.timeout # pylint:disable=no-member
TIMEOUT_ERROR = socket.timeout # pylint:disable=no-member
def _setup_listener(self):
listener, raw_listener = ssl_listener(self.privfile, self.certfile)
......@@ -44,7 +54,7 @@ class TestSSL(test__socket.TestTCP):
def create_connection(self, *args, **kwargs): # pylint:disable=signature-differs
return self._close_on_teardown(
# pylint:disable=deprecated-method
ssl.wrap_socket(super(TestSSL, self).create_connection(*args, **kwargs)))
wrap_socket(super(TestSSL, self).create_connection(*args, **kwargs)))
# The SSL library can take a long time to buffer the large amount of data we're trying
# to send, so we can't compare to the timeout values
......
......@@ -39,6 +39,9 @@ __imports__ += [
# non-Python (native) APIs, so we shouldn't mess with it.
__imports__.append('get_native_id')
# Added to 3.12
if hasattr(__thread__, 'daemon_threads_allowed'):
__imports__.append('daemon_threads_allowed')
error = __thread__.error
......
......@@ -374,7 +374,20 @@ class GreenletTree(object):
@staticmethod
def __render_tb(tree, label, frame, limit):
tree.child_data(label)
tb = ''.join(traceback.format_stack(frame, limit))
# XXX: Issues with tblib?
# 3.12b3 is crashing walking the stack on macOS;
# on Linux CI, it is failing with a nice attribute error
# (which watches where the macOS is failing, inside a call to
# Py_GetAttr):
#
# File "/opt/hostedtoolcache/Python/3.12.0-beta.3/x64/lib/python3.12/traceback.py", line 339, in walk_stack
# yield f, f.f_lineno
# AttributeError: 'dict' object has no attribute 'f_lineno'
if sys.version_info != (3, 12, 0, 'beta', 3):
tb = ''.join(traceback.format_stack(frame, limit))
else:
tb = ''
tree.child_multidata(tb)
@staticmethod
......
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