Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drop python 3.7 support, drop pypy3.7-3.8, add pypy3.10 (except on windows) #2668

Merged
merged 23 commits into from
Jul 17, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fc81dee
drop python 3.7 support
jakkdl Jun 23, 2023
7cf58b2
remove more code, mark lines with pragma: no cover, update test-requi…
jakkdl Jun 24, 2023
3cacea9
stop special-casing IPPROTO_IPV6 entirely
jakkdl Jun 24, 2023
98379e4
remove disable_threading_excepthook
jakkdl Jun 25, 2023
7bc0826
run pyupgrade --py38-plus
jakkdl Jun 26, 2023
45e22a8
also run it on the notes-to-self directory
jakkdl Jun 26, 2023
7d5b484
drop pypy-3.8, add pypy-3.10 and pypy-3.10-nightly to CI
jakkdl Jul 1, 2023
04f1792
leave pypy-3.10 for a different PR, re-fix tuple->Tuple mypy fail on 3.8
jakkdl Jul 1, 2023
b3366e1
revert dropping pypy3.10, bump cryptography
jakkdl Jul 3, 2023
951b996
fix f401 CI
jakkdl Jul 3, 2023
087998c
add pypy3.10 on windows, test limiting cryptography to <41
jakkdl Jul 3, 2023
29f44a5
update req.txt to actually limit cryptography <41
jakkdl Jul 3, 2023
4dc2241
drop pypy3.8, try crypto41 + pypy3.9
jakkdl Jul 3, 2023
e9ac69d
drop windows pypy3.10 from CI
jakkdl Jul 3, 2023
19b3aac
clean up test_requirements.in
jakkdl Jul 3, 2023
050ba35
update readme clarifying pypy version requirement
jakkdl Jul 3, 2023
8590621
fixes after CI review from A5rocks
jakkdl Jul 6, 2023
44d4ee3
revert version requirement on typing-extensions, add newsfragments
jakkdl Jul 7, 2023
0991961
Merge branch 'main' into drop_3.7
jakkdl Jul 7, 2023
63dfc70
Merge branch 'main' into drop_3.7
jakkdl Jul 7, 2023
e3771d8
Update 2668.headline.rst
jakkdl Jul 11, 2023
a2a4fd2
fix capitalization in newsfragment, headline->removal, add removal to…
jakkdl Jul 17, 2023
08c972b
Merge remote-tracking branch 'origin/master' into drop_3.7
jakkdl Jul 17, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ 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.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'
#- python: 'pypy-3.10-nightly'
# arch: 'x86'
jakkdl marked this conversation as resolved.
Show resolved Hide resolved
include:
- python: '3.8'
arch: 'x64'
Expand Down Expand Up @@ -66,7 +66,7 @@ jobs:
# support this for PyPy presently so we get no help there.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note to self: test if this is supported yet. It probably works!

#
# CPython -> 3.9.0-alpha - 3.9.X
# PyPy -> pypy-3.7
# PyPy -> pypy-3.9
jakkdl marked this conversation as resolved.
Show resolved Hide resolved
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
Expand All @@ -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.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:
Expand Down Expand Up @@ -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.9-nightly', 'pypy-3.10-nightly']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mind adding at least pypy 3.10 here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to pypy-3.10-nightly? Ubuntu tests both pypy-3.10 and pypy-3.10-nightly, windows & mac has always only tested pypy-nightlies (no clue why they do that instead of the stable releases though)

continue-on-error: >-
${{
(
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 currently maintaned versions of PyPy3 are
both fine), and are using Linux, macOS, Windows, or FreeBSD, then Trio
jakkdl marked this conversation as resolved.
Show resolved Hide resolved
will work. Other environments might work too, but those
are the ones we test on. And all of our dependencies are pure Python,
Expand Down
2 changes: 1 addition & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 3 additions & 8 deletions docs/source/reference-core.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
jakkdl marked this conversation as resolved.
Show resolved Hide resolved
Here's a toy example demonstrating how to use :mod:`contextvars`:

.. literalinclude:: reference-core/contextvar-example.py
Expand Down Expand Up @@ -1009,7 +1004,7 @@ Example output (yours may differ slightly):
request 0: Request received finished

For more information, read the
`contextvars docs <https://docs.python.org/3.7/library/contextvars.html>`__.
`contextvars docs <https://docs.python.org/3/library/contextvars.html>`__.


.. _synchronization:
Expand Down
2 changes: 1 addition & 1 deletion docs/source/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 17 additions & 9 deletions notes-to-self/how-does-windows-so-reuseaddr-work.py
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand All @@ -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))
Expand All @@ -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)
Expand All @@ -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):
Expand All @@ -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])
)
10 changes: 6 additions & 4 deletions notes-to-self/reopen-pipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -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...")

Expand Down Expand Up @@ -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 --")
Expand All @@ -63,6 +65,6 @@ def sleep_then_write():

print("-- testing socketpair --")
import socket

rs, ws = socket.socketpair()
check_reopen(rs.fileno(), ws.fileno())

8 changes: 6 additions & 2 deletions notes-to-self/schedule-timing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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)
2 changes: 1 addition & 1 deletion notes-to-self/socketpair-buffering.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@
except BlockingIOError:
pass

print("setsockopt bufsize {}: {}".format(bufsize, i))
print(f"setsockopt bufsize {bufsize}: {i}")
a.close()
b.close()
22 changes: 15 additions & 7 deletions notes-to-self/ssl-handshake/ssl-handshake.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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()
Expand Down Expand Up @@ -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"
Expand All @@ -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:
Expand All @@ -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"
Expand Down
4 changes: 3 additions & 1 deletion notes-to-self/sslobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@
soutb = ssl.MemoryBIO()
sso = server_ctx.wrap_bio(sinb, soutb, server_side=True)


@contextmanager
def expect(etype):
try:
yield
except etype:
pass
else:
raise AssertionError("expected {}".format(etype))
raise AssertionError(f"expected {etype}")


with expect(ssl.SSLWantReadError):
cso.do_handshake()
Expand Down
8 changes: 6 additions & 2 deletions notes-to-self/thread-closure-bug-demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Loading