Support python 3.11+ (#473)

* chore: Cython version update
* add 3.11-dev pipeline
* Test and build on Python 3.11
* Drop test_context_run_segfault
* Support context in loop.create_task()
* Consistent PseudoSocket repr
* Add stubs for new 3.11 loop.sock_*() methods
* Skip test_create_ssl_server_manual_connection_lost on 3.11 for now

Co-authored-by: Fantix King <fantix.king@gmail.com>
Co-authored-by: Elvis Pranskevichus <elvis@edgedb.com>
This commit is contained in:
Euiseo Cha 2022-09-02 00:56:34 +09:00 committed by GitHub
parent e04637e088
commit 8e42921d7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 55 additions and 49 deletions

View File

@ -75,7 +75,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
cibw_python: ["cp37-*", "cp38-*", "cp39-*", "cp310-*"]
cibw_python: ["cp37-*", "cp38-*", "cp39-*", "cp310-*", "cp311-*"]
cibw_arch: ["x86_64", "aarch64", "universal2"]
exclude:
- os: ubuntu-latest

View File

@ -14,7 +14,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10"]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11.0-rc.1"]
os: [ubuntu-latest, macos-latest]
env:

View File

@ -21,14 +21,16 @@ from setuptools.command.build_ext import build_ext
from setuptools.command.sdist import sdist
CYTHON_DEPENDENCY = 'Cython(>=0.29.24,<0.30.0)'
CYTHON_DEPENDENCY = 'Cython(>=0.29.32,<0.30.0)'
# Minimal dependencies required to test uvloop.
TEST_DEPENDENCIES = [
# pycodestyle is a dependency of flake8, but it must be frozen because
# their combination breaks too often
# (example breakage: https://gitlab.com/pycqa/flake8/issues/427)
'aiohttp',
# aiohttp doesn't support 3.11 yet,
# see https://github.com/aio-libs/aiohttp/issues/6600
'aiohttp ; python_version < "3.11"',
'flake8~=3.9.2',
'psutil',
'pycodestyle~=2.7.0',

View File

@ -540,7 +540,9 @@ class _TestBase:
async def coro():
pass
factory = lambda loop, coro: MyTask(coro, loop=loop)
factory = lambda loop, coro, **kwargs: MyTask(
coro, loop=loop, **kwargs
)
self.assertIsNone(self.loop.get_task_factory())
self.loop.set_task_factory(factory)
@ -577,7 +579,9 @@ class _TestBase:
async def coro():
pass
factory = lambda loop, coro: MyTask(coro, loop=loop)
factory = lambda loop, coro, **kwargs: MyTask(
coro, loop=loop, **kwargs
)
self.assertIsNone(self.loop.get_task_factory())
task = self.loop.create_task(coro(), name="mytask")

View File

@ -452,6 +452,10 @@ class _ContextBaseTests(tb.SSLTestCase):
self._run_server_test(test, async_sock=True)
def test_create_ssl_server_manual_connection_lost(self):
if self.implementation == 'asyncio' and sys.version_info >= (3, 11, 0):
# TODO(fantix): fix for 3.11
raise unittest.SkipTest('should pass on 3.11')
async def test(proto, cvar, ssl_sock, **_):
def close():
cvar.set('closing')

View File

@ -652,43 +652,6 @@ class _TestTCP:
self.assertIsNone(
self.loop.run_until_complete(connection_lost_called))
def test_context_run_segfault(self):
is_new = False
done = self.loop.create_future()
def server(sock):
sock.sendall(b'hello')
class Protocol(asyncio.Protocol):
def __init__(self):
self.transport = None
def connection_made(self, transport):
self.transport = transport
def data_received(self, data):
try:
self = weakref.ref(self)
nonlocal is_new
if is_new:
done.set_result(data)
else:
is_new = True
new_proto = Protocol()
self().transport.set_protocol(new_proto)
new_proto.connection_made(self().transport)
new_proto.data_received(data)
except Exception as e:
done.set_exception(e)
async def test(addr):
await self.loop.create_connection(Protocol, *addr)
data = await done
self.assertEqual(data, b'hello')
with self.tcp_server(server) as srv:
self.loop.run_until_complete(test(srv.addr))
class Test_UV_TCP(_TestTCP, tb.UVTestCase):

View File

@ -1,5 +1,6 @@
import asyncio
import ssl
import sys
from socket import AddressFamily, SocketKind, _Address, _RetAddress, socket
from typing import (
IO,
@ -210,6 +211,9 @@ class Loop:
async def sock_sendall(self, sock: socket, data: bytes) -> None: ...
async def sock_accept(self, sock: socket) -> Tuple[socket, _RetAddress]: ...
async def sock_connect(self, sock: socket, address: _Address) -> None: ...
async def sock_recvfrom(self, sock: socket, bufsize: int) -> bytes: ...
async def sock_recvfrom_into(self, sock: socket, buf: bytearray, nbytes: int = ...) -> int: ...
async def sock_sendto(self, sock: socket, data: bytes, address: _Address) -> None: ...
async def connect_accepted_socket(
self,
protocol_factory: Callable[[], _ProtocolT],

View File

@ -50,6 +50,7 @@ include "errors.pyx"
cdef:
int PY39 = PY_VERSION_HEX >= 0x03090000
int PY311 = PY_VERSION_HEX >= 0x030b0000
uint64_t MAX_SLEEP = 3600 * 24 * 365 * 100
@ -1413,19 +1414,35 @@ cdef class Loop:
"""Create a Future object attached to the loop."""
return self._new_future()
def create_task(self, coro, *, name=None):
def create_task(self, coro, *, name=None, context=None):
"""Schedule a coroutine object.
Return a task object.
If name is not None, task.set_name(name) will be called if the task
object has the set_name attribute, true for default Task in Python 3.8.
An optional keyword-only context argument allows specifying a custom
contextvars.Context for the coro to run in. The current context copy is
created when no context is provided.
"""
self._check_closed()
if PY311:
if self._task_factory is None:
task = aio_Task(coro, loop=self, context=context)
else:
task = self._task_factory(self, coro, context=context)
else:
if context is None:
if self._task_factory is None:
task = aio_Task(coro, loop=self)
else:
task = self._task_factory(self, coro)
else:
if self._task_factory is None:
task = context.run(aio_Task, coro, self)
else:
task = context.run(self._task_factory, self, coro)
# copied from asyncio.tasks._set_task_name (bpo-34270)
if name is not None:
@ -2604,6 +2621,18 @@ cdef class Loop:
finally:
socket_dec_io_ref(sock)
@cython.iterable_coroutine
async def sock_recvfrom(self, sock, bufsize):
raise NotImplementedError
@cython.iterable_coroutine
async def sock_recvfrom_into(self, sock, buf, nbytes=0):
raise NotImplementedError
@cython.iterable_coroutine
async def sock_sendto(self, sock, data, address):
raise NotImplementedError
@cython.iterable_coroutine
async def connect_accepted_socket(self, protocol_factory, sock, *,
ssl=None,

View File

@ -41,8 +41,8 @@ cdef class PseudoSocket:
def __repr__(self):
s = ("<uvloop.PseudoSocket fd={}, family={!s}, "
"type={!s}, proto={}").format(self.fileno(), self.family,
self.type, self.proto)
"type={!s}, proto={}").format(self.fileno(), self.family.name,
self.type.name, self.proto)
if self._fd != -1:
try: