From fc81dee8f87044273beb3d15cddd45a6c2505152 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Fri, 23 Jun 2023 14:02:37 +0200 Subject: [PATCH 01/20] drop python 3.7 support --- .github/workflows/ci.yml | 8 ++++---- README.rst | 2 +- docs/source/index.rst | 2 +- docs/source/reference-core.rst | 11 +++-------- docs/source/tutorial.rst | 2 +- setup.py | 6 +++--- test-requirements.in | 12 ++---------- trio/_socket.py | 8 +------- trio/_tests/test_ssl.py | 10 ---------- trio/_util.py | 1 + 10 files changed, 17 insertions(+), 45 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 480398a1f0..ca341e5390 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - python: ['3.7', '3.8', '3.9', '3.10', 'pypy-3.8-nightly', 'pypy-3.9-nightly'] + python: ['3.8', '3.9', '3.10', 'pypy-3.8-nightly', 'pypy-3.9-nightly'] arch: ['x86', 'x64'] lsp: [''] lsp_extract_file: [''] @@ -66,7 +66,7 @@ jobs: # support this for PyPy presently so we get no help there. # # CPython -> 3.9.0-alpha - 3.9.X - # PyPy -> pypy-3.7 + # PyPy -> pypy-3.9 python-version: ${{ fromJSON(format('["{0}", "{1}"]', format('{0}.0-alpha - {0}.X', matrix.python), matrix.python))[startsWith(matrix.python, 'pypy')] }} architecture: '${{ matrix.arch }}' cache: pip @@ -92,7 +92,7 @@ jobs: strategy: fail-fast: false matrix: - python: ['pypy-3.7', 'pypy-3.8', 'pypy-3.9', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12-dev', 'pypy-3.8-nightly', 'pypy-3.9-nightly'] + python: ['pypy-3.8', 'pypy-3.9', '3.8', '3.9', '3.10', '3.11', '3.12-dev', 'pypy-3.8-nightly', 'pypy-3.9-nightly'] check_formatting: ['0'] extra_name: [''] include: @@ -143,7 +143,7 @@ jobs: strategy: fail-fast: false matrix: - python: ['3.7', '3.8', '3.9', '3.10', 'pypy-3.8-nightly', 'pypy-3.9-nightly'] + python: ['3.8', '3.9', '3.10', 'pypy-3.8-nightly', 'pypy-3.9-nightly'] continue-on-error: >- ${{ ( diff --git a/README.rst b/README.rst index 4e096eddf3..d2d80ce7cb 100644 --- a/README.rst +++ b/README.rst @@ -92,7 +92,7 @@ demonstration of implementing the "Happy Eyeballs" algorithm in an older library versus Trio. **Cool, but will it work on my system?** Probably! As long as you have -some kind of Python 3.7-or-better (CPython or the latest PyPy3 are +some kind of Python 3.8-or-better (CPython or the latest PyPy3 are both fine), and are using Linux, macOS, Windows, or FreeBSD, then Trio will work. Other environments might work too, but those are the ones we test on. And all of our dependencies are pure Python, diff --git a/docs/source/index.rst b/docs/source/index.rst index 84d81880af..fc13227c3a 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -45,7 +45,7 @@ Vital statistics: * Supported environments: We test on - - Python: 3.7+ (CPython and PyPy) + - Python: 3.8+ (CPython and PyPy) - Windows, macOS, Linux (glibc and musl), FreeBSD Other environments might also work; give it a try and see. diff --git a/docs/source/reference-core.rst b/docs/source/reference-core.rst index 922ae4680e..f9b305fe78 100644 --- a/docs/source/reference-core.rst +++ b/docs/source/reference-core.rst @@ -974,13 +974,8 @@ work. What we need is something that's *like* a global variable, but that can have different values depending on which request handler is accessing it. -To solve this problem, Python 3.7 added a new module to the standard -library: :mod:`contextvars`. And not only does Trio have built-in -support for :mod:`contextvars`, but if you're using an earlier version -of Python, then Trio makes sure that a backported version of -:mod:`contextvars` is installed. So you can assume :mod:`contextvars` -is there and works regardless of what version of Python you're using. - +To solve this problem, Python has a module in the standard +library: :mod:`contextvars`. Here's a toy example demonstrating how to use :mod:`contextvars`: .. literalinclude:: reference-core/contextvar-example.py @@ -1009,7 +1004,7 @@ Example output (yours may differ slightly): request 0: Request received finished For more information, read the -`contextvars docs `__. +`contextvars docs `__. .. _synchronization: diff --git a/docs/source/tutorial.rst b/docs/source/tutorial.rst index 19289ca991..0faffd119b 100644 --- a/docs/source/tutorial.rst +++ b/docs/source/tutorial.rst @@ -88,7 +88,7 @@ Okay, ready? Let's get started. Before you begin ---------------- -1. Make sure you're using Python 3.7 or newer. +1. Make sure you're using Python 3.8 or newer. 2. ``python3 -m pip install --upgrade trio`` (or on Windows, maybe ``py -3 -m pip install --upgrade trio`` – `details diff --git a/setup.py b/setup.py index c13d1eb78a..a0d2d5eaaf 100644 --- a/setup.py +++ b/setup.py @@ -44,7 +44,7 @@ Vital statistics: * Supported environments: Linux, macOS, or Windows running some kind of Python - 3.7-or-better (either CPython or PyPy3 is fine). \\*BSD and illumos likely + 3.8-or-better (either CPython or PyPy3 is fine). \\*BSD and illumos likely work too, but are not tested. * Install: ``python3 -m pip install -U trio`` (or on Windows, maybe @@ -96,7 +96,7 @@ # This means, just install *everything* you see under trio/, even if it # doesn't look like a source file, so long as it appears in MANIFEST.in: include_package_data=True, - python_requires=">=3.7", + python_requires=">=3.8", keywords=["async", "io", "networking", "trio"], classifiers=[ "Development Status :: 3 - Alpha", @@ -110,11 +110,11 @@ "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: System :: Networking", "Framework :: Trio", ], diff --git a/test-requirements.in b/test-requirements.in index 1e1e23c2b8..6e24774168 100644 --- a/test-requirements.in +++ b/test-requirements.in @@ -4,7 +4,7 @@ coverage >= 7.2.5 async_generator >= 1.9 pyright # ipython 7.x is the last major version supporting Python 3.7 -ipython < 7.35 # for the IPython traceback integration tests +ipython # for the IPython traceback integration tests pyOpenSSL >= 22.0.0 # for the ssl + DTLS tests trustme # for the ssl + DTLS tests pylint # for pylint finding all symbols tests @@ -15,14 +15,12 @@ cryptography>=36.0.0 # 35.0.0 is transitive but fails black; implementation_name == "cpython" mypy; implementation_name == "cpython" types-pyOpenSSL; implementation_name == "cpython" -flake8 < 6.0.0 # 6.0.0 drops python 3.7 +flake8 flake8-pyproject astor # code generation pip-tools >= 6.13.0 # https://github.com/python-trio/trio/pull/654#issuecomment-420518745 -# typed_ast is deprecated as of 3.8, and straight up doesn't compile on 3.10-dev as of 2021-12-13 -typed_ast; implementation_name == "cpython" and python_version < "3.8" mypy-extensions; implementation_name == "cpython" typing-extensions < 4.7.0 @@ -34,9 +32,3 @@ idna outcome sniffio exceptiongroup >= 1.0.0rc9; python_version < "3.11" - -# isort 5.12.0 requires python 3.8 -isort < 5.12.0 - -# cryptography 40.0.2 (and presumably prior) segfaults on PyPy 3.7 -cryptography < 40.0.0 diff --git a/trio/_socket.py b/trio/_socket.py index 2889f48113..e246aa99d1 100644 --- a/trio/_socket.py +++ b/trio/_socket.py @@ -47,13 +47,7 @@ async def __aexit__(self, etype, value, tb): # CONSTANTS ################################################################ -try: - from socket import IPPROTO_IPV6 -except ImportError: - # Before Python 3.8, Windows is missing IPPROTO_IPV6 - # https://bugs.python.org/issue29515 - if sys.platform == "win32": # pragma: no branch - IPPROTO_IPV6 = 41 +from socket import IPPROTO_IPV6 ################################################################ # Overrides diff --git a/trio/_tests/test_ssl.py b/trio/_tests/test_ssl.py index 234290e185..f0f87caf3f 100644 --- a/trio/_tests/test_ssl.py +++ b/trio/_tests/test_ssl.py @@ -67,12 +67,6 @@ TRIO_TEST_1_CERT.configure_cert(SERVER_CTX) -skip_on_broken_openssl: MarkDecorator = pytest.mark.skipif( - sys.version_info < (3, 8) and ssl.OPENSSL_VERSION_INFO[0] > 1, - reason="Python 3.7 does not work with OpenSSL versions higher than 1.X", -) - - # TLS 1.3 has a lot of changes from previous versions. So we want to run tests # with both TLS 1.3, and TLS 1.2. # "tls13" means that we're willing to negotiate TLS 1.3. Usually that's @@ -821,7 +815,6 @@ async def test_send_all_empty_string(client_ctx): await s.aclose() -@skip_on_broken_openssl @pytest.mark.parametrize("https_compatible", [False, True]) async def test_SSLStream_generic(client_ctx, https_compatible): async def stream_maker(): @@ -1037,7 +1030,6 @@ async def test_ssl_bad_shutdown(client_ctx): await server.aclose() -@skip_on_broken_openssl async def test_ssl_bad_shutdown_but_its_ok(client_ctx): client, server = ssl_memory_stream_pair( client_ctx, @@ -1102,7 +1094,6 @@ def close_hook(): assert transport_close_count == 1 -@skip_on_broken_openssl async def test_ssl_https_compatibility_disagreement(client_ctx): client, server = ssl_memory_stream_pair( client_ctx, @@ -1127,7 +1118,6 @@ async def receive_and_expect_error(): nursery.start_soon(receive_and_expect_error) -@skip_on_broken_openssl async def test_https_mode_eof_before_handshake(client_ctx): client, server = ssl_memory_stream_pair( client_ctx, diff --git a/trio/_util.py b/trio/_util.py index b60e0104e8..31a61a9cbf 100644 --- a/trio/_util.py +++ b/trio/_util.py @@ -139,6 +139,7 @@ def _return_value_looks_like_wrong_library(value): # function. So we have to just call it and then check whether the # return value is a coroutine object. # Note: will not be necessary on python>=3.8, see https://bugs.python.org/issue34890 + # TODO: python3.7 support is now dropped, so the above can be addressed. if not isinstance(coro, collections.abc.Coroutine): # Give good error for: nursery.start_soon(func_returning_future) if _return_value_looks_like_wrong_library(coro): From 7cf58b203355beb34ab3b90fe9bc9feffc50b278 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Sat, 24 Jun 2023 15:38:56 +0200 Subject: [PATCH 02/20] remove more code, mark lines with pragma: no cover, update test-requirements.txt --- test-requirements.txt | 4 +-- trio/_core/_tests/test_multierror.py | 4 +-- trio/_core/_tests/tutil.py | 45 +++++++++++----------------- trio/_path.py | 4 +-- trio/_tests/test_ssl.py | 16 ---------- 5 files changed, 21 insertions(+), 52 deletions(-) diff --git a/test-requirements.txt b/test-requirements.txt index 6babde688e..2feda84220 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -57,9 +57,7 @@ iniconfig==2.0.0 ipython==7.34.0 # via -r test-requirements.in isort==5.11.5 - # via - # -r test-requirements.in - # pylint + # via pylint jedi==0.18.2 # via # -r test-requirements.in diff --git a/trio/_core/_tests/test_multierror.py b/trio/_core/_tests/test_multierror.py index 354f6e01df..61a0bd5a53 100644 --- a/trio/_core/_tests/test_multierror.py +++ b/trio/_core/_tests/test_multierror.py @@ -479,9 +479,7 @@ def run_script(name, use_ipython=False): def check_simple_excepthook(completed, uses_ipython): assert_match_in_seq( [ - "in = (3, 8) - else "in ", + "in ", "MultiError", "--- 1 ---", "in exc1_fn", diff --git a/trio/_core/_tests/tutil.py b/trio/_core/_tests/tutil.py index dc9a4f486d..e66127d20a 100644 --- a/trio/_core/_tests/tutil.py +++ b/trio/_core/_tests/tutil.py @@ -43,7 +43,7 @@ with s: try: s.bind(("::1", 0)) - except OSError: + except OSError: # pragma: no cover # since support for 3.7 was removed can_bind_ipv6 = False else: can_bind_ipv6 = True @@ -86,37 +86,26 @@ def _noop(*args, **kwargs): pass -if sys.version_info >= (3, 8): - - @contextmanager - def restore_unraisablehook(): - sys.unraisablehook, prev = sys.__unraisablehook__, sys.unraisablehook - try: - yield - finally: - sys.unraisablehook = prev - - @contextmanager - def disable_threading_excepthook(): - if sys.version_info >= (3, 10): - threading.excepthook, prev = threading.__excepthook__, threading.excepthook - else: - threading.excepthook, prev = _noop, threading.excepthook - - try: - yield - finally: - threading.excepthook = prev +@contextmanager +def restore_unraisablehook(): + sys.unraisablehook, prev = sys.__unraisablehook__, sys.unraisablehook + try: + yield + finally: + sys.unraisablehook = prev -else: - @contextmanager - def restore_unraisablehook(): # pragma: no cover - yield +@contextmanager +def disable_threading_excepthook(): # pragma: no cover # not used + if sys.version_info >= (3, 10): + threading.excepthook, prev = threading.__excepthook__, threading.excepthook + else: + threading.excepthook, prev = _noop, threading.excepthook - @contextmanager - def disable_threading_excepthook(): # pragma: no cover + try: yield + finally: + threading.excepthook = prev # template is like: diff --git a/trio/_path.py b/trio/_path.py index bb81759ecf..67234e223d 100644 --- a/trio/_path.py +++ b/trio/_path.py @@ -246,14 +246,14 @@ async def open(self, *args, **kwargs): is_mount: Any owner: Any - if sys.version_info >= (3, 8) and sys.version_info < (3, 12): - link_to: Any if sys.version_info >= (3, 9): is_relative_to: Any with_stem: Any readlink: Any if sys.version_info >= (3, 10): hardlink_to: Any + if sys.version_info < (3, 12): + link_to: Any if sys.version_info >= (3, 12): is_junction: Any walk: Any diff --git a/trio/_tests/test_ssl.py b/trio/_tests/test_ssl.py index f0f87caf3f..09be505096 100644 --- a/trio/_tests/test_ssl.py +++ b/trio/_tests/test_ssl.py @@ -109,22 +109,6 @@ def ssl_echo_serve_sync(sock, *, expect_fail=False): wrapped.unwrap() except exceptions: pass - except ssl.SSLWantWriteError: # pragma: no cover - # Under unclear conditions, CPython sometimes raises - # SSLWantWriteError here. This is a bug (bpo-32219), - # but it's not our bug. Christian Heimes thinks - # it's fixed in 'recent' CPython versions so we fail - # the test for those and ignore it for earlier - # versions. - if ( - sys.implementation.name != "cpython" - or sys.version_info >= (3, 8) - ): - pytest.fail( - "still an issue on recent python versions " - "add a comment to " - "https://bugs.python.org/issue32219" - ) return wrapped.sendall(data) # This is an obscure workaround for an openssl bug. In server mode, in From 3cacea914ba9f0d54c46b6bc51a1e9cb9910d22f Mon Sep 17 00:00:00 2001 From: jakkdl Date: Sat, 24 Jun 2023 15:58:35 +0200 Subject: [PATCH 03/20] stop special-casing IPPROTO_IPV6 entirely --- trio/_socket.py | 8 +------- trio/socket.py | 4 +--- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/trio/_socket.py b/trio/_socket.py index e246aa99d1..828f6d0260 100644 --- a/trio/_socket.py +++ b/trio/_socket.py @@ -43,12 +43,6 @@ async def __aexit__(self, etype, value, tb): return False -################################################################ -# CONSTANTS -################################################################ - -from socket import IPPROTO_IPV6 - ################################################################ # Overrides ################################################################ @@ -543,7 +537,7 @@ async def wait_writable(self): async def _resolve_address_nocp(self, address, *, local): if self.family == _stdlib_socket.AF_INET6: ipv6_v6only = self._sock.getsockopt( - IPPROTO_IPV6, _stdlib_socket.IPV6_V6ONLY + _stdlib_socket.IPPROTO_IPV6, _stdlib_socket.IPV6_V6ONLY ) else: ipv6_v6only = False diff --git a/trio/socket.py b/trio/socket.py index 6d3ed366d4..16c6799e3b 100644 --- a/trio/socket.py +++ b/trio/socket.py @@ -79,9 +79,6 @@ except ImportError: pass -# get names used by Trio that we define on our own -from ._socket import IPPROTO_IPV6 as IPPROTO_IPV6 - if _t.TYPE_CHECKING: IP_BIND_ADDRESS_NO_PORT: int else: @@ -164,6 +161,7 @@ IPPROTO_IGMP as IPPROTO_IGMP, IPPROTO_GGP as IPPROTO_GGP, IPPROTO_IPV4 as IPPROTO_IPV4, + IPPROTO_IPV6 as IPPROTO_IPV6, IPPROTO_IPIP as IPPROTO_IPIP, IPPROTO_TCP as IPPROTO_TCP, IPPROTO_EGP as IPPROTO_EGP, From 98379e4129bbd017c4015b5a92566e1f10c9270b Mon Sep 17 00:00:00 2001 From: jakkdl Date: Sun, 25 Jun 2023 09:34:27 +0200 Subject: [PATCH 04/20] remove disable_threading_excepthook --- trio/_core/_tests/tutil.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/trio/_core/_tests/tutil.py b/trio/_core/_tests/tutil.py index e66127d20a..31bc59e4cb 100644 --- a/trio/_core/_tests/tutil.py +++ b/trio/_core/_tests/tutil.py @@ -95,19 +95,6 @@ def restore_unraisablehook(): sys.unraisablehook = prev -@contextmanager -def disable_threading_excepthook(): # pragma: no cover # not used - if sys.version_info >= (3, 10): - threading.excepthook, prev = threading.__excepthook__, threading.excepthook - else: - threading.excepthook, prev = _noop, threading.excepthook - - try: - yield - finally: - threading.excepthook = prev - - # template is like: # [1, {2.1, 2.2}, 3] -> matches [1, 2.1, 2.2, 3] or [1, 2.2, 2.1, 3] def check_sequence_matches(seq, template): From 7bc082650f31ed72443ebb23f6288d5d3470b7e7 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 26 Jun 2023 17:31:24 +0200 Subject: [PATCH 05/20] run pyupgrade --py38-plus --- trio/_channel.py | 6 +++--- trio/_core/_run.py | 4 ++-- trio/_tests/test_exports.py | 2 +- trio/_unix_pipes.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/trio/_channel.py b/trio/_channel.py index 3ad08b7109..e777d48c73 100644 --- a/trio/_channel.py +++ b/trio/_channel.py @@ -96,7 +96,7 @@ def _open_memory_channel( if TYPE_CHECKING: # written as a class so you can say open_memory_channel[int](5) # Need to use Tuple instead of tuple due to CI check running on 3.8 - class open_memory_channel(Tuple[MemorySendChannel[T], MemoryReceiveChannel[T]]): + class open_memory_channel(tuple[MemorySendChannel[T], MemoryReceiveChannel[T]]): def __new__( # type: ignore[misc] # "must return a subtype" cls, max_buffer_size: int ) -> tuple[MemorySendChannel[T], MemoryReceiveChannel[T]]: @@ -215,7 +215,7 @@ def abort_fn(_: RaiseCancelT) -> Abort: # Return type must be stringified or use a TypeVar @enable_ki_protection - def clone(self) -> "MemorySendChannel[SendType]": + def clone(self) -> MemorySendChannel[SendType]: """Clone this send channel object. This returns a new `MemorySendChannel` object, which acts as a @@ -358,7 +358,7 @@ def abort_fn(_: RaiseCancelT) -> Abort: return await trio.lowlevel.wait_task_rescheduled(abort_fn) # type: ignore[no-any-return] @enable_ki_protection - def clone(self) -> "MemoryReceiveChannel[ReceiveType]": + def clone(self) -> MemoryReceiveChannel[ReceiveType]: """Clone this receive channel object. This returns a new `MemoryReceiveChannel` object, which acts as a diff --git a/trio/_core/_run.py b/trio/_core/_run.py index c07e29ab97..5f471884af 100644 --- a/trio/_core/_run.py +++ b/trio/_core/_run.py @@ -46,7 +46,7 @@ if TYPE_CHECKING: # An unfortunate name collision here with trio._util.Final - from typing_extensions import Final as FinalT + from typing import Final as FinalT DEADLINE_HEAP_MIN_PRUNE_THRESHOLD: FinalT = 1000 @@ -1312,7 +1312,7 @@ def raise_cancel(): class RunContext(threading.local): - runner: "Runner" + runner: Runner task: Task diff --git a/trio/_tests/test_exports.py b/trio/_tests/test_exports.py index 9006f8a8ef..01e90d63f9 100644 --- a/trio/_tests/test_exports.py +++ b/trio/_tests/test_exports.py @@ -263,7 +263,7 @@ def no_hidden(symbols): cache_json = json.loads(cache_file.read()) # skip a bunch of file-system activity (probably can un-memoize?) - @functools.lru_cache() + @functools.lru_cache def lookup_symbol(symbol): topname, *modname, name = symbol.split(".") version = next(cache.glob("3.*/")) diff --git a/trio/_unix_pipes.py b/trio/_unix_pipes.py index fa98e79521..1575dbcfc9 100644 --- a/trio/_unix_pipes.py +++ b/trio/_unix_pipes.py @@ -10,7 +10,7 @@ import trio if TYPE_CHECKING: - from typing_extensions import Final as FinalType + from typing import Final as FinalType if os.name != "posix": # We raise an error here rather than gating the import in lowlevel.py From 45e22a8ac62f03fce7b335f87ceac0066a8377fa Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 26 Jun 2023 17:33:15 +0200 Subject: [PATCH 06/20] also run it on the notes-to-self directory --- .../how-does-windows-so-reuseaddr-work.py | 26 ++++++++++++------- notes-to-self/reopen-pipe.py | 10 ++++--- notes-to-self/schedule-timing.py | 8 ++++-- notes-to-self/socketpair-buffering.py | 2 +- notes-to-self/ssl-handshake/ssl-handshake.py | 22 +++++++++++----- notes-to-self/sslobject.py | 4 ++- notes-to-self/thread-closure-bug-demo.py | 8 ++++-- notes-to-self/thread-dispatch-bench.py | 5 +++- .../time-wait-windows-exclusiveaddruse.py | 8 +++--- notes-to-self/time-wait.py | 7 +++-- 10 files changed, 68 insertions(+), 32 deletions(-) diff --git a/notes-to-self/how-does-windows-so-reuseaddr-work.py b/notes-to-self/how-does-windows-so-reuseaddr-work.py index 4865ea17b3..d8d60d1d66 100644 --- a/notes-to-self/how-does-windows-so-reuseaddr-work.py +++ b/notes-to-self/how-does-windows-so-reuseaddr-work.py @@ -10,6 +10,7 @@ modes = ["default", "SO_REUSEADDR", "SO_EXCLUSIVEADDRUSE"] bind_types = ["wildcard", "specific"] + def sock(mode): s = socket.socket(family=socket.AF_INET) if mode == "SO_REUSEADDR": @@ -18,6 +19,7 @@ def sock(mode): s.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1) return s + def bind(sock, bind_type): if bind_type == "wildcard": sock.bind(("0.0.0.0", 12345)) @@ -26,6 +28,7 @@ def bind(sock, bind_type): else: assert False + def table_entry(mode1, bind_type1, mode2, bind_type2): with sock(mode1) as sock1: bind(sock1, bind_type1) @@ -41,19 +44,22 @@ def table_entry(mode1, bind_type1, mode2, bind_type2): else: return "Success" -print(""" + +print( + """ second bind | """ -+ " | ".join(["%-19s" % mode for mode in modes]) + + " | ".join(["%-19s" % mode for mode in modes]) ) -print(""" """, end='') +print(""" """, end="") for mode in modes: - print(" | " + " | ".join(["%8s" % bind_type for bind_type in bind_types]), end='') + print(" | " + " | ".join(["%8s" % bind_type for bind_type in bind_types]), end="") -print(""" +print( + """ first bind -----------------------------------------------------------------""" -# default | wildcard | INUSE | Success | ACCESS | Success | INUSE | Success + # default | wildcard | INUSE | Success | ACCESS | Success | INUSE | Success ) for i, mode1 in enumerate(modes): @@ -63,6 +69,8 @@ def table_entry(mode1, bind_type1, mode2, bind_type2): for l, bind_type2 in enumerate(bind_types): entry = table_entry(mode1, bind_type1, mode2, bind_type2) row.append(entry) - #print(mode1, bind_type1, mode2, bind_type2, entry) - print("{:>19} | {:>8} | ".format(mode1, bind_type1) - + " | ".join(["%8s" % entry for entry in row])) + # print(mode1, bind_type1, mode2, bind_type2, entry) + print( + f"{mode1:>19} | {bind_type1:>8} | " + + " | ".join(["%8s" % entry for entry in row]) + ) diff --git a/notes-to-self/reopen-pipe.py b/notes-to-self/reopen-pipe.py index 910def397c..5e5b31e41f 100644 --- a/notes-to-self/reopen-pipe.py +++ b/notes-to-self/reopen-pipe.py @@ -3,12 +3,13 @@ import time import tempfile + def check_reopen(r1, w): try: print("Reopening read end") - r2 = os.open("/proc/self/fd/{}".format(r1), os.O_RDONLY) + r2 = os.open(f"/proc/self/fd/{r1}", os.O_RDONLY) - print("r1 is {}, r2 is {}".format(r1, r2)) + print(f"r1 is {r1}, r2 is {r2}") print("checking they both can receive from w...") @@ -36,11 +37,12 @@ def check_reopen(r1, w): def sleep_then_write(): time.sleep(1) os.write(w, b"c") + threading.Thread(target=sleep_then_write, daemon=True).start() assert os.read(r1, 1) == b"c" print("r1 definitely seems to be in blocking mode") except Exception as exc: - print("ERROR: {!r}".format(exc)) + print(f"ERROR: {exc!r}") print("-- testing anonymous pipe --") @@ -63,6 +65,6 @@ def sleep_then_write(): print("-- testing socketpair --") import socket + rs, ws = socket.socketpair() check_reopen(rs.fileno(), ws.fileno()) - diff --git a/notes-to-self/schedule-timing.py b/notes-to-self/schedule-timing.py index c3093066e2..176dcf9220 100644 --- a/notes-to-self/schedule-timing.py +++ b/notes-to-self/schedule-timing.py @@ -4,16 +4,18 @@ LOOPS = 0 RUNNING = True + async def reschedule_loop(depth): if depth == 0: global LOOPS while RUNNING: LOOPS += 1 await trio.sleep(0) - #await trio.lowlevel.cancel_shielded_checkpoint() + # await trio.lowlevel.cancel_shielded_checkpoint() else: await reschedule_loop(depth - 1) + async def report_loop(): global RUNNING try: @@ -25,13 +27,15 @@ async def report_loop(): end_count = LOOPS loops = end_count - start_count duration = end_time - start_time - print("{} loops/sec".format(loops / duration)) + print(f"{loops / duration} loops/sec") finally: RUNNING = False + async def main(): async with trio.open_nursery() as nursery: nursery.start_soon(reschedule_loop, 10) nursery.start_soon(report_loop) + trio.run(main) diff --git a/notes-to-self/socketpair-buffering.py b/notes-to-self/socketpair-buffering.py index dd3b1ad97d..5e77a709b7 100644 --- a/notes-to-self/socketpair-buffering.py +++ b/notes-to-self/socketpair-buffering.py @@ -32,6 +32,6 @@ except BlockingIOError: pass - print("setsockopt bufsize {}: {}".format(bufsize, i)) + print(f"setsockopt bufsize {bufsize}: {i}") a.close() b.close() diff --git a/notes-to-self/ssl-handshake/ssl-handshake.py b/notes-to-self/ssl-handshake/ssl-handshake.py index 81d875be6a..18a0e1a675 100644 --- a/notes-to-self/ssl-handshake/ssl-handshake.py +++ b/notes-to-self/ssl-handshake/ssl-handshake.py @@ -8,6 +8,7 @@ server_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) server_ctx.load_cert_chain("trio-test-1.pem") + def _ssl_echo_serve_sync(sock): try: wrapped = server_ctx.wrap_socket(sock, server_side=True) @@ -20,16 +21,19 @@ def _ssl_echo_serve_sync(sock): except BrokenPipeError: pass + @contextmanager def echo_server_connection(): client_sock, server_sock = socket.socketpair() with client_sock, server_sock: t = threading.Thread( - target=_ssl_echo_serve_sync, args=(server_sock,), daemon=True) + target=_ssl_echo_serve_sync, args=(server_sock,), daemon=True + ) t.start() yield client_sock + class ManuallyWrappedSocket: def __init__(self, ctx, sock, **kwargs): self.incoming = ssl.MemoryBIO() @@ -82,21 +86,23 @@ def unwrap(self): def wrap_socket_via_wrap_socket(ctx, sock, **kwargs): return ctx.wrap_socket(sock, do_handshake_on_connect=False, **kwargs) + def wrap_socket_via_wrap_bio(ctx, sock, **kwargs): return ManuallyWrappedSocket(ctx, sock, **kwargs) for wrap_socket in [ - wrap_socket_via_wrap_socket, - wrap_socket_via_wrap_bio, + wrap_socket_via_wrap_socket, + wrap_socket_via_wrap_bio, ]: - print("\n--- checking {} ---\n".format(wrap_socket.__name__)) + print(f"\n--- checking {wrap_socket.__name__} ---\n") print("checking with do_handshake + correct hostname...") with echo_server_connection() as client_sock: client_ctx = ssl.create_default_context(cafile="trio-test-CA.pem") wrapped = wrap_socket( - client_ctx, client_sock, server_hostname="trio-test-1.example.org") + client_ctx, client_sock, server_hostname="trio-test-1.example.org" + ) wrapped.do_handshake() wrapped.sendall(b"x") assert wrapped.recv(1) == b"x" @@ -107,7 +113,8 @@ def wrap_socket_via_wrap_bio(ctx, sock, **kwargs): with echo_server_connection() as client_sock: client_ctx = ssl.create_default_context(cafile="trio-test-CA.pem") wrapped = wrap_socket( - client_ctx, client_sock, server_hostname="trio-test-2.example.org") + client_ctx, client_sock, server_hostname="trio-test-2.example.org" + ) try: wrapped.do_handshake() except Exception: @@ -119,7 +126,8 @@ def wrap_socket_via_wrap_bio(ctx, sock, **kwargs): with echo_server_connection() as client_sock: client_ctx = ssl.create_default_context(cafile="trio-test-CA.pem") wrapped = wrap_socket( - client_ctx, client_sock, server_hostname="trio-test-2.example.org") + client_ctx, client_sock, server_hostname="trio-test-2.example.org" + ) # We forgot to call do_handshake # But the hostname is wrong so something had better error out... sent = b"x" diff --git a/notes-to-self/sslobject.py b/notes-to-self/sslobject.py index cfac98676e..0692af319c 100644 --- a/notes-to-self/sslobject.py +++ b/notes-to-self/sslobject.py @@ -15,6 +15,7 @@ soutb = ssl.MemoryBIO() sso = server_ctx.wrap_bio(sinb, soutb, server_side=True) + @contextmanager def expect(etype): try: @@ -22,7 +23,8 @@ def expect(etype): except etype: pass else: - raise AssertionError("expected {}".format(etype)) + raise AssertionError(f"expected {etype}") + with expect(ssl.SSLWantReadError): cso.do_handshake() diff --git a/notes-to-self/thread-closure-bug-demo.py b/notes-to-self/thread-closure-bug-demo.py index 514636a1b4..b09a87fe5f 100644 --- a/notes-to-self/thread-closure-bug-demo.py +++ b/notes-to-self/thread-closure-bug-demo.py @@ -8,18 +8,21 @@ COUNT = 100 + def slow_tracefunc(frame, event, arg): # A no-op trace function that sleeps briefly to make us more likely to hit # the race condition. time.sleep(0.01) return slow_tracefunc + def run_with_slow_tracefunc(fn): # settrace() only takes effect when you enter a new frame, so we need this # little dance: sys.settrace(slow_tracefunc) return fn() + def outer(): x = 0 # We hide the done variable inside a list, because we want to use it to @@ -46,13 +49,14 @@ def traced_looper(): t.start() for i in range(COUNT): - print("after {} increments, x is {}".format(i, x)) + print(f"after {i} increments, x is {x}") x += 1 time.sleep(0.01) done[0] = True t.join() - print("Final discrepancy: {} (should be 0)".format(COUNT - x)) + print(f"Final discrepancy: {COUNT - x} (should be 0)") + outer() diff --git a/notes-to-self/thread-dispatch-bench.py b/notes-to-self/thread-dispatch-bench.py index 1625efae17..9afb4bbec8 100644 --- a/notes-to-self/thread-dispatch-bench.py +++ b/notes-to-self/thread-dispatch-bench.py @@ -10,11 +10,13 @@ COUNT = 10000 + def worker(in_q, out_q): while True: job = in_q.get() out_q.put(job()) + def main(): in_q = Queue() out_q = Queue() @@ -28,6 +30,7 @@ def main(): in_q.put(lambda: None) out_q.get() end = time.monotonic() - print("{:.2f} µs/job".format((end - start) / COUNT * 1e6)) + print(f"{(end - start) / COUNT * 1e6:.2f} µs/job") + main() diff --git a/notes-to-self/time-wait-windows-exclusiveaddruse.py b/notes-to-self/time-wait-windows-exclusiveaddruse.py index db3aaad08a..dcb4a27dd0 100644 --- a/notes-to-self/time-wait-windows-exclusiveaddruse.py +++ b/notes-to-self/time-wait-windows-exclusiveaddruse.py @@ -8,15 +8,17 @@ import socket from contextlib import contextmanager + @contextmanager def report_outcome(tagline): try: yield except OSError as exc: - print("{}: failed".format(tagline)) - print(" details: {!r}".format(exc)) + print(f"{tagline}: failed") + print(f" details: {exc!r}") else: - print("{}: succeeded".format(tagline)) + print(f"{tagline}: succeeded") + # Set up initial listening socket lsock = socket.socket() diff --git a/notes-to-self/time-wait.py b/notes-to-self/time-wait.py index e865a94982..08c71b0048 100644 --- a/notes-to-self/time-wait.py +++ b/notes-to-self/time-wait.py @@ -31,6 +31,7 @@ import attr + @attr.s(repr=False) class Options: listen1_early = attr.ib(default=None) @@ -49,9 +50,10 @@ def describe(self): for f in attr.fields(self.__class__): value = getattr(self, f.name) if value is not None: - info.append("{}={}".format(f.name, value)) + info.append(f"{f.name}={value}") return "Set/unset: {}".format(", ".join(info)) + def time_wait(options): print(options.describe()) @@ -60,7 +62,7 @@ def time_wait(options): listen0 = socket.socket() listen0.bind(("127.0.0.1", 0)) sockaddr = listen0.getsockname() - #print(" ", sockaddr) + # print(" ", sockaddr) listen0.close() listen1 = socket.socket() @@ -98,6 +100,7 @@ def time_wait(options): else: print(" -> ok") + time_wait(Options()) time_wait(Options(listen1_early=True, server=True, listen2=True)) time_wait(Options(listen1_early=True)) From 7d5b48451a4214ec92e011dab8fcf5bd23a83856 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Sat, 1 Jul 2023 13:33:35 +0200 Subject: [PATCH 07/20] drop pypy-3.8, add pypy-3.10 and pypy-3.10-nightly to CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca341e5390..444537d5dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,7 +92,7 @@ jobs: strategy: fail-fast: false matrix: - python: ['pypy-3.8', 'pypy-3.9', '3.8', '3.9', '3.10', '3.11', '3.12-dev', 'pypy-3.8-nightly', 'pypy-3.9-nightly'] + python: ['pypy-3.9', 'pypy-3.10', '3.8', '3.9', '3.10', '3.11', '3.12-dev', 'pypy-3.9-nightly', 'pypy-3.10-nightly'] check_formatting: ['0'] extra_name: [''] include: From 04f17923697b347c33cd74c0429632e0472c654a Mon Sep 17 00:00:00 2001 From: jakkdl Date: Sat, 1 Jul 2023 13:50:27 +0200 Subject: [PATCH 08/20] leave pypy-3.10 for a different PR, re-fix tuple->Tuple mypy fail on 3.8 --- .github/workflows/ci.yml | 2 +- trio/_channel.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 444537d5dc..bc725132f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,7 +92,7 @@ jobs: strategy: fail-fast: false matrix: - python: ['pypy-3.9', 'pypy-3.10', '3.8', '3.9', '3.10', '3.11', '3.12-dev', 'pypy-3.9-nightly', 'pypy-3.10-nightly'] + python: ['pypy-3.9', '3.8', '3.9', '3.10', '3.11', '3.12-dev', 'pypy-3.9-nightly'] check_formatting: ['0'] extra_name: [''] include: diff --git a/trio/_channel.py b/trio/_channel.py index e777d48c73..bbea43608c 100644 --- a/trio/_channel.py +++ b/trio/_channel.py @@ -96,7 +96,7 @@ def _open_memory_channel( if TYPE_CHECKING: # written as a class so you can say open_memory_channel[int](5) # Need to use Tuple instead of tuple due to CI check running on 3.8 - class open_memory_channel(tuple[MemorySendChannel[T], MemoryReceiveChannel[T]]): + class open_memory_channel(Tuple[MemorySendChannel[T], MemoryReceiveChannel[T]]): def __new__( # type: ignore[misc] # "must return a subtype" cls, max_buffer_size: int ) -> tuple[MemorySendChannel[T], MemoryReceiveChannel[T]]: From b3366e1f97ec0af1081ec185f397a5bb6a15408a Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 3 Jul 2023 12:22:58 +0200 Subject: [PATCH 09/20] revert dropping pypy3.10, bump cryptography --- .github/workflows/ci.yml | 2 +- test-requirements.in | 2 +- test-requirements.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc725132f4..444537d5dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,7 +92,7 @@ jobs: strategy: fail-fast: false matrix: - python: ['pypy-3.9', '3.8', '3.9', '3.10', '3.11', '3.12-dev', 'pypy-3.9-nightly'] + python: ['pypy-3.9', 'pypy-3.10', '3.8', '3.9', '3.10', '3.11', '3.12-dev', 'pypy-3.9-nightly', 'pypy-3.10-nightly'] check_formatting: ['0'] extra_name: [''] include: diff --git a/test-requirements.in b/test-requirements.in index 6e24774168..2ba5ba5404 100644 --- a/test-requirements.in +++ b/test-requirements.in @@ -9,7 +9,7 @@ pyOpenSSL >= 22.0.0 # for the ssl + DTLS tests trustme # for the ssl + DTLS tests pylint # for pylint finding all symbols tests jedi # for jedi code completion tests -cryptography>=36.0.0 # 35.0.0 is transitive but fails +cryptography>=40.0.0 # 35.0.0 is transitive but fails # Tools black; implementation_name == "cpython" diff --git a/test-requirements.txt b/test-requirements.txt index 2feda84220..17fa0a099a 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -28,7 +28,7 @@ click==8.1.3 # pip-tools coverage==7.2.7 # via -r test-requirements.in -cryptography==39.0.2 +cryptography==41.0.1 # via # -r test-requirements.in # pyopenssl From 951b996e027a8d9cf774b30e050b49f2febf977f Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 3 Jul 2023 12:40:00 +0200 Subject: [PATCH 10/20] fix f401 CI --- trio/_core/_tests/tutil.py | 1 - trio/_tests/test_ssl.py | 3 --- 2 files changed, 4 deletions(-) diff --git a/trio/_core/_tests/tutil.py b/trio/_core/_tests/tutil.py index 31bc59e4cb..b907dbe576 100644 --- a/trio/_core/_tests/tutil.py +++ b/trio/_core/_tests/tutil.py @@ -1,7 +1,6 @@ # Utilities for testing import asyncio import socket as stdlib_socket -import threading import os import sys from typing import TYPE_CHECKING diff --git a/trio/_tests/test_ssl.py b/trio/_tests/test_ssl.py index 09be505096..6e3ad1cb44 100644 --- a/trio/_tests/test_ssl.py +++ b/trio/_tests/test_ssl.py @@ -35,9 +35,6 @@ check_two_way_stream, ) -if TYPE_CHECKING: - from _pytest.mark import MarkDecorator - # We have two different kinds of echo server fixtures we use for testing. The # first is a real server written using the stdlib ssl module and blocking From 087998c326323bb8794afaf7d11731dfad69b4a1 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 3 Jul 2023 12:47:27 +0200 Subject: [PATCH 11/20] add pypy3.10 on windows, test limiting cryptography to <41 --- .github/workflows/ci.yml | 2 +- test-requirements.in | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 444537d5dc..726ccdf8c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - python: ['3.8', '3.9', '3.10', 'pypy-3.8-nightly', 'pypy-3.9-nightly'] + python: ['3.8', '3.9', '3.10', 'pypy-3.8-nightly', 'pypy-3.9-nightly', 'pypy-3.10-nightly'] arch: ['x86', 'x64'] lsp: [''] lsp_extract_file: [''] diff --git a/test-requirements.in b/test-requirements.in index 2ba5ba5404..1d29a1a386 100644 --- a/test-requirements.in +++ b/test-requirements.in @@ -32,3 +32,6 @@ idna outcome sniffio exceptiongroup >= 1.0.0rc9; python_version < "3.11" + + +cryptography<41 From 29f44a5f705b5024d1a92b297ac91e4fca55b45b Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 3 Jul 2023 13:06:21 +0200 Subject: [PATCH 12/20] update req.txt to actually limit cryptography <41 --- test-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-requirements.txt b/test-requirements.txt index 17fa0a099a..80be8e9d8d 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -28,7 +28,7 @@ click==8.1.3 # pip-tools coverage==7.2.7 # via -r test-requirements.in -cryptography==41.0.1 +cryptography==40.0.2 # via # -r test-requirements.in # pyopenssl From 4dc224165dc00ea3ae0f04de4af948acb4b0f741 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 3 Jul 2023 13:35:08 +0200 Subject: [PATCH 13/20] drop pypy3.8, try crypto41 + pypy3.9 --- .github/workflows/ci.yml | 6 ++---- test-requirements.in | 5 +++-- test-requirements.txt | 2 +- trio/_tests/test_ssl.py | 1 - 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 726ccdf8c7..460b02f0ee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,14 +18,12 @@ jobs: strategy: fail-fast: false matrix: - python: ['3.8', '3.9', '3.10', 'pypy-3.8-nightly', 'pypy-3.9-nightly', 'pypy-3.10-nightly'] + python: ['3.8', '3.9', '3.10', 'pypy-3.9-nightly', 'pypy-3.10-nightly'] arch: ['x86', 'x64'] lsp: [''] lsp_extract_file: [''] extra_name: [''] exclude: - - python: 'pypy-3.8-nightly' - arch: 'x86' - python: 'pypy-3.9-nightly' arch: 'x86' include: @@ -143,7 +141,7 @@ jobs: strategy: fail-fast: false matrix: - python: ['3.8', '3.9', '3.10', 'pypy-3.8-nightly', 'pypy-3.9-nightly'] + python: ['3.8', '3.9', '3.10', 'pypy-3.9-nightly', 'pypy-3.10-nightly'] continue-on-error: >- ${{ ( diff --git a/test-requirements.in b/test-requirements.in index 1d29a1a386..85aa99b340 100644 --- a/test-requirements.in +++ b/test-requirements.in @@ -9,7 +9,6 @@ pyOpenSSL >= 22.0.0 # for the ssl + DTLS tests trustme # for the ssl + DTLS tests pylint # for pylint finding all symbols tests jedi # for jedi code completion tests -cryptography>=40.0.0 # 35.0.0 is transitive but fails # Tools black; implementation_name == "cpython" @@ -34,4 +33,6 @@ sniffio exceptiongroup >= 1.0.0rc9; python_version < "3.11" -cryptography<41 +# cryptography41 segfaults on pypy3.8 and pypy3.9 on windows +cryptography>=41 +#cryptography<41; python_version < "3.10" diff --git a/test-requirements.txt b/test-requirements.txt index 80be8e9d8d..17fa0a099a 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -28,7 +28,7 @@ click==8.1.3 # pip-tools coverage==7.2.7 # via -r test-requirements.in -cryptography==40.0.2 +cryptography==41.0.1 # via # -r test-requirements.in # pyopenssl diff --git a/trio/_tests/test_ssl.py b/trio/_tests/test_ssl.py index 6e3ad1cb44..bc2bd878fa 100644 --- a/trio/_tests/test_ssl.py +++ b/trio/_tests/test_ssl.py @@ -2,7 +2,6 @@ import os import sys -from typing import TYPE_CHECKING import pytest From e9ac69d44b7e90d0c3998b378143901baf585cee Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 3 Jul 2023 13:49:25 +0200 Subject: [PATCH 14/20] drop windows pypy3.10 from CI --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 460b02f0ee..6d013599c3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - python: ['3.8', '3.9', '3.10', 'pypy-3.9-nightly', 'pypy-3.10-nightly'] + python: ['3.8', '3.9', '3.10', 'pypy-3.9-nightly']#, 'pypy-3.10-nightly'] arch: ['x86', 'x64'] lsp: [''] lsp_extract_file: [''] @@ -26,6 +26,8 @@ jobs: exclude: - python: 'pypy-3.9-nightly' arch: 'x86' + #- python: 'pypy-3.10-nightly' + # arch: 'x86' include: - python: '3.8' arch: 'x64' From 19b3aacd6ae4366e0adf85ef6db48a8d0933dbc0 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 3 Jul 2023 13:54:13 +0200 Subject: [PATCH 15/20] clean up test_requirements.in --- test-requirements.in | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/test-requirements.in b/test-requirements.in index 85aa99b340..860c67e6c3 100644 --- a/test-requirements.in +++ b/test-requirements.in @@ -3,12 +3,12 @@ pytest >= 5.0 # for faulthandler in core coverage >= 7.2.5 async_generator >= 1.9 pyright -# ipython 7.x is the last major version supporting Python 3.7 ipython # for the IPython traceback integration tests pyOpenSSL >= 22.0.0 # for the ssl + DTLS tests trustme # for the ssl + DTLS tests pylint # for pylint finding all symbols tests jedi # for jedi code completion tests +cryptography>=41.0.0 # cryptography<41 segfaults on pypy3.10 # Tools black; implementation_name == "cpython" @@ -31,8 +31,3 @@ idna outcome sniffio exceptiongroup >= 1.0.0rc9; python_version < "3.11" - - -# cryptography41 segfaults on pypy3.8 and pypy3.9 on windows -cryptography>=41 -#cryptography<41; python_version < "3.10" From 050ba35be708cf45f3fdf51b5d6aa9ec82365097 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 3 Jul 2023 13:57:24 +0200 Subject: [PATCH 16/20] update readme clarifying pypy version requirement --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index d2d80ce7cb..94329ed6fc 100644 --- a/README.rst +++ b/README.rst @@ -92,7 +92,7 @@ demonstration of implementing the "Happy Eyeballs" algorithm in an older library versus Trio. **Cool, but will it work on my system?** Probably! As long as you have -some kind of Python 3.8-or-better (CPython or the latest PyPy3 are +some kind of Python 3.8-or-better (CPython or currently maintaned versions of PyPy3 are both fine), and are using Linux, macOS, Windows, or FreeBSD, then Trio will work. Other environments might work too, but those are the ones we test on. And all of our dependencies are pure Python, From 8590621d65c5f80562d3d489b10ada288751cea1 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Thu, 6 Jul 2023 14:33:39 +0200 Subject: [PATCH 17/20] fixes after CI review from A5rocks --- .github/workflows/ci.yml | 12 +++++++----- README.rst | 5 +++-- docs/source/reference-core.rst | 1 + pyproject.toml | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d013599c3..40af0960f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,16 +18,18 @@ jobs: strategy: fail-fast: false matrix: - python: ['3.8', '3.9', '3.10', 'pypy-3.9-nightly']#, 'pypy-3.10-nightly'] + # pypy-3.10 is failing, see https://github.com/python-trio/trio/issues/2678 + python: ['3.8', '3.9', '3.10', 'pypy-3.9-nightly'] #, 'pypy-3.10-nightly'] arch: ['x86', 'x64'] lsp: [''] lsp_extract_file: [''] extra_name: [''] exclude: + # pypy does not release 32-bit binaries - python: 'pypy-3.9-nightly' arch: 'x86' - #- python: 'pypy-3.10-nightly' - # arch: 'x86' + #- python: 'pypy-3.10-nightly' + # arch: 'x86' include: - python: '3.8' arch: 'x64' @@ -65,8 +67,8 @@ jobs: # and then finally an actual release version. actions/setup-python doesn't # support this for PyPy presently so we get no help there. # - # CPython -> 3.9.0-alpha - 3.9.X - # PyPy -> pypy-3.9 + # 'CPython' -> '3.9.0-alpha - 3.9.X' + # 'PyPy' -> 'pypy-3.9' python-version: ${{ fromJSON(format('["{0}", "{1}"]', format('{0}.0-alpha - {0}.X', matrix.python), matrix.python))[startsWith(matrix.python, 'pypy')] }} architecture: '${{ matrix.arch }}' cache: pip diff --git a/README.rst b/README.rst index 94329ed6fc..016823e1f5 100644 --- a/README.rst +++ b/README.rst @@ -92,8 +92,9 @@ demonstration of implementing the "Happy Eyeballs" algorithm in an older library versus Trio. **Cool, but will it work on my system?** Probably! As long as you have -some kind of Python 3.8-or-better (CPython or currently maintaned versions of PyPy3 are -both fine), and are using Linux, macOS, Windows, or FreeBSD, then Trio +some kind of Python 3.8-or-better (CPython or [currently maintained versions of +PyPy3](https://doc.pypy.org/en/latest/faq.html#which-python-versions-does-pypy-implement) +are both fine), and are using Linux, macOS, Windows, or FreeBSD, then Trio will work. Other environments might work too, but those are the ones we test on. And all of our dependencies are pure Python, except for CFFI on Windows, which has wheels available, so diff --git a/docs/source/reference-core.rst b/docs/source/reference-core.rst index f9b305fe78..5b0d0e433a 100644 --- a/docs/source/reference-core.rst +++ b/docs/source/reference-core.rst @@ -976,6 +976,7 @@ accessing it. To solve this problem, Python has a module in the standard library: :mod:`contextvars`. + Here's a toy example demonstrating how to use :mod:`contextvars`: .. literalinclude:: reference-core/contextvar-example.py diff --git a/pyproject.toml b/pyproject.toml index 0cce1106b7..1f8816f44c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.black] -target-version = ['py37'] +target-version = ['py38'] [tool.flake8] extend-ignore = ['D', 'E', 'W', 'F403', 'F405', 'F821', 'F822'] From 44d4ee3c01e1086c4f939207e419b801dd0a996d Mon Sep 17 00:00:00 2001 From: jakkdl Date: Fri, 7 Jul 2023 12:17:00 +0200 Subject: [PATCH 18/20] revert version requirement on typing-extensions, add newsfragments --- newsfragments/2668.headline.rst | 1 + test-requirements.in | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 newsfragments/2668.headline.rst diff --git a/newsfragments/2668.headline.rst b/newsfragments/2668.headline.rst new file mode 100644 index 0000000000..6ad10f4601 --- /dev/null +++ b/newsfragments/2668.headline.rst @@ -0,0 +1 @@ +Drop support for python3.7, pypy3.7 and pypy3.8. diff --git a/test-requirements.in b/test-requirements.in index 860c67e6c3..03997ad2e7 100644 --- a/test-requirements.in +++ b/test-requirements.in @@ -21,7 +21,7 @@ pip-tools >= 6.13.0 # https://github.com/python-trio/trio/pull/654#issuecomment-420518745 mypy-extensions; implementation_name == "cpython" -typing-extensions < 4.7.0 +typing-extensions # Trio's own dependencies cffi; os_name == "nt" From e3771d84e2fddaaca09345e46a24f632acc8b3dc Mon Sep 17 00:00:00 2001 From: John Litborn <11260241+jakkdl@users.noreply.github.com> Date: Tue, 11 Jul 2023 15:19:45 +0200 Subject: [PATCH 19/20] Update 2668.headline.rst --- newsfragments/2668.headline.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/newsfragments/2668.headline.rst b/newsfragments/2668.headline.rst index 6ad10f4601..a9b449d525 100644 --- a/newsfragments/2668.headline.rst +++ b/newsfragments/2668.headline.rst @@ -1 +1 @@ -Drop support for python3.7, pypy3.7 and pypy3.8. +Drop support for python3.7 and pypy3.7/3.8. From a2a4fd274d13a04c056a3a5c0ff8ab68f400cac0 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 17 Jul 2023 09:34:02 +0200 Subject: [PATCH 20/20] fix capitalization in newsfragment, headline->removal, add removal to newsfragments/README.rst --- newsfragments/2668.headline.rst | 1 - newsfragments/2668.removal.rst | 1 + newsfragments/README.rst | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 newsfragments/2668.headline.rst create mode 100644 newsfragments/2668.removal.rst diff --git a/newsfragments/2668.headline.rst b/newsfragments/2668.headline.rst deleted file mode 100644 index a9b449d525..0000000000 --- a/newsfragments/2668.headline.rst +++ /dev/null @@ -1 +0,0 @@ -Drop support for python3.7 and pypy3.7/3.8. diff --git a/newsfragments/2668.removal.rst b/newsfragments/2668.removal.rst new file mode 100644 index 0000000000..512f681077 --- /dev/null +++ b/newsfragments/2668.removal.rst @@ -0,0 +1 @@ +Drop support for Python3.7 and PyPy3.7/3.8. diff --git a/newsfragments/README.rst b/newsfragments/README.rst index 349e67eec0..52dc0716bb 100644 --- a/newsfragments/README.rst +++ b/newsfragments/README.rst @@ -14,6 +14,7 @@ Each file should be named like ``..rst``, where deprecated features after an appropriate time, go in the ``deprecated`` category instead) * ``feature``: any new feature that doesn't qualify for ``headline`` +* ``removal``: removing support for old python versions, or other removals with no deprecation period. * ``bugfix`` * ``doc`` * ``deprecated``