From bdfffb6b585cc66480c35b6e2d696b6e2ea45e76 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Sun, 29 Sep 2024 00:57:40 -0500 Subject: [PATCH 01/52] Enable `flake8-annotations` --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index ff4aa3460..781fd8249 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -106,6 +106,7 @@ allowed-confusables = ["–"] select = [ "A", # flake8-builtins + "ANN", # flake8-annotations "ASYNC", # flake8-async "B", # flake8-bugbear "C4", # flake8-comprehensions @@ -132,6 +133,8 @@ select = [ ] extend-ignore = [ 'A002', # builtin-argument-shadowing + 'ANN101', # missing-type-self + 'ANN102', # missing-type-cls 'E402', # module-import-not-at-top-of-file (usually OS-specific) 'E501', # line-too-long 'F403', # undefined-local-with-import-star From acdb7b2c424a2f91f8f98e63010e423b2dc49358 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Sun, 29 Sep 2024 00:59:37 -0500 Subject: [PATCH 02/52] Autofix `ANN204` --- notes-to-self/afd-lab.py | 6 ++--- notes-to-self/aio-guest-test.py | 8 +++--- notes-to-self/atomic-local.py | 2 +- notes-to-self/blocking-read-hack.py | 2 +- notes-to-self/estimate-task-size.py | 4 +-- notes-to-self/graceful-shutdown-idea.py | 8 +++--- .../how-does-windows-so-reuseaddr-work.py | 4 +-- notes-to-self/loopy.py | 4 +-- notes-to-self/lots-of-tasks.py | 2 +- notes-to-self/measure-listen-backlog.py | 2 +- notes-to-self/ntp-example.py | 2 +- notes-to-self/print-task-tree.py | 8 +++--- notes-to-self/proxy-benchmarks.py | 26 +++++++++---------- notes-to-self/reopen-pipe.py | 4 +-- notes-to-self/schedule-timing.py | 6 ++--- notes-to-self/socket-scaling.py | 4 +-- .../ssl-close-notify/ssl-close-notify.py | 2 +- notes-to-self/ssl-handshake/ssl-handshake.py | 8 +++--- notes-to-self/thread-closure-bug-demo.py | 2 +- notes-to-self/thread-dispatch-bench.py | 4 +-- notes-to-self/time-wait.py | 4 +-- notes-to-self/trace.py | 26 +++++++++---------- notes-to-self/trivial-err.py | 11 ++++---- notes-to-self/trivial.py | 2 +- notes-to-self/wakeup-fd-racer.py | 6 ++--- notes-to-self/win-waitable-timer.py | 4 +-- src/trio/_channel.py | 2 +- src/trio/_core/_instrumentation.py | 2 +- src/trio/_core/_mock_clock.py | 2 +- src/trio/_core/_run.py | 2 +- src/trio/_dtls.py | 2 +- src/trio/_highlevel_socket.py | 4 +-- src/trio/_repl.py | 2 +- src/trio/_socket.py | 4 +-- src/trio/_sync.py | 6 ++--- src/trio/testing/_check_streams.py | 2 +- src/trio/testing/_fake_net.py | 2 +- src/trio/testing/_memory_streams.py | 8 +++--- src/trio/testing/_raises_group.py | 14 +++++----- 39 files changed, 107 insertions(+), 106 deletions(-) diff --git a/notes-to-self/afd-lab.py b/notes-to-self/afd-lab.py index a95eb8bfd..1a52ff17f 100644 --- a/notes-to-self/afd-lab.py +++ b/notes-to-self/afd-lab.py @@ -99,7 +99,7 @@ class AFDLab: - def __init__(self): + def __init__(self) -> None: self._afd = _afd_helper_handle() trio.lowlevel.register_with_iocp(self._afd) @@ -141,7 +141,7 @@ async def afd_poll(self, sock, flags, *, exclusive=0): return out_flags -def fill_socket(sock): +def fill_socket(sock) -> None: try: while True: sock.send(b"x" * 65536) @@ -149,7 +149,7 @@ def fill_socket(sock): pass -async def main(): +async def main() -> None: afdlab = AFDLab() a, b = socket.socketpair() diff --git a/notes-to-self/aio-guest-test.py b/notes-to-self/aio-guest-test.py index 3c607d028..4995fafec 100644 --- a/notes-to-self/aio-guest-test.py +++ b/notes-to-self/aio-guest-test.py @@ -3,12 +3,12 @@ import trio -async def aio_main(): +async def aio_main() -> None: loop = asyncio.get_running_loop() trio_done_fut = loop.create_future() - def trio_done_callback(main_outcome): + def trio_done_callback(main_outcome) -> None: print(f"trio_main finished: {main_outcome!r}") trio_done_fut.set_result(main_outcome) @@ -21,7 +21,7 @@ def trio_done_callback(main_outcome): (await trio_done_fut).unwrap() -async def trio_main(): +async def trio_main() -> None: print("trio_main!") to_trio, from_aio = trio.open_memory_channel(float("inf")) @@ -40,7 +40,7 @@ async def trio_main(): del _task_ref -async def aio_pingpong(from_trio, to_trio): +async def aio_pingpong(from_trio, to_trio) -> None: print("aio_pingpong!") while True: diff --git a/notes-to-self/atomic-local.py b/notes-to-self/atomic-local.py index 643bc16c6..b0db7ed2b 100644 --- a/notes-to-self/atomic-local.py +++ b/notes-to-self/atomic-local.py @@ -4,7 +4,7 @@ sentinel = "_unique_name" -def f(): +def f() -> None: print(locals()) diff --git a/notes-to-self/blocking-read-hack.py b/notes-to-self/blocking-read-hack.py index 688f10305..a5d486123 100644 --- a/notes-to-self/blocking-read-hack.py +++ b/notes-to-self/blocking-read-hack.py @@ -19,7 +19,7 @@ async def blocking_read_with_timeout( print("reading from fd", fd) cancel_requested = False - async def kill_it_after_timeout(new_fd): + async def kill_it_after_timeout(new_fd) -> None: print("sleeping") await trio.sleep(timeout) print("breaking the fd") diff --git a/notes-to-self/estimate-task-size.py b/notes-to-self/estimate-task-size.py index 0010c7a2b..7a618af7d 100644 --- a/notes-to-self/estimate-task-size.py +++ b/notes-to-self/estimate-task-size.py @@ -9,7 +9,7 @@ HIGH = 10000 -async def tinytask(): +async def tinytask() -> None: await trio.sleep_forever() @@ -22,7 +22,7 @@ async def measure(count): return resource.getrusage(resource.RUSAGE_SELF) -async def main(): +async def main() -> None: low_usage = await measure(LOW) high_usage = await measure(HIGH + LOW) diff --git a/notes-to-self/graceful-shutdown-idea.py b/notes-to-self/graceful-shutdown-idea.py index 9497af972..36e9178ad 100644 --- a/notes-to-self/graceful-shutdown-idea.py +++ b/notes-to-self/graceful-shutdown-idea.py @@ -5,11 +5,11 @@ class GracefulShutdownManager: - def __init__(self): + def __init__(self) -> None: self._shutting_down = False self._cancel_scopes = set() - def start_shutdown(self): + def start_shutdown(self) -> None: self._shutting_down = True for cancel_scope in self._cancel_scopes: cancel_scope.cancel() @@ -32,7 +32,7 @@ def shutting_down(self): # When doing operations that might block for an indefinite about of time and # that should be aborted when a graceful shutdown starts, wrap them in 'with # gsm.cancel_on_graceful_shutdown()'. -async def stream_handler(stream): +async def stream_handler(stream) -> None: while True: with gsm.cancel_on_graceful_shutdown(): data = await stream.receive_some() @@ -42,7 +42,7 @@ async def stream_handler(stream): # To trigger the shutdown: -async def listen_for_shutdown_signals(): +async def listen_for_shutdown_signals() -> None: with trio.open_signal_receiver(signal.SIGINT, signal.SIGTERM) as signal_aiter: async for _sig in signal_aiter: gsm.start_shutdown() 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 f87e957ad..cb6264844 100644 --- a/notes-to-self/how-does-windows-so-reuseaddr-work.py +++ b/notes-to-self/how-does-windows-so-reuseaddr-work.py @@ -20,7 +20,7 @@ def sock(mode): return s -def bind(sock, bind_type): +def bind(sock, bind_type) -> None: if bind_type == "wildcard": sock.bind(("0.0.0.0", 12345)) elif bind_type == "specific": @@ -29,7 +29,7 @@ def bind(sock, bind_type): raise AssertionError() -def table_entry(mode1, bind_type1, mode2, bind_type2): +def table_entry(mode1, bind_type1, mode2, bind_type2) -> str: with sock(mode1) as sock1: bind(sock1, bind_type1) try: diff --git a/notes-to-self/loopy.py b/notes-to-self/loopy.py index 99f6e050b..e6065bbf7 100644 --- a/notes-to-self/loopy.py +++ b/notes-to-self/loopy.py @@ -3,7 +3,7 @@ import trio -async def loopy(): +async def loopy() -> None: try: while True: # synchronous sleep to avoid maxing out CPU @@ -13,7 +13,7 @@ async def loopy(): print("KI!") -async def main(): +async def main() -> None: async with trio.open_nursery() as nursery: nursery.start_soon(loopy) nursery.start_soon(loopy) diff --git a/notes-to-self/lots-of-tasks.py b/notes-to-self/lots-of-tasks.py index 048c69a7e..d83617552 100644 --- a/notes-to-self/lots-of-tasks.py +++ b/notes-to-self/lots-of-tasks.py @@ -6,7 +6,7 @@ COUNT = int(COUNT_STR) -async def main(): +async def main() -> None: async with trio.open_nursery() as nursery: for _ in range(COUNT): nursery.start_soon(trio.sleep, 1) diff --git a/notes-to-self/measure-listen-backlog.py b/notes-to-self/measure-listen-backlog.py index b7253b86c..7704ee7d4 100644 --- a/notes-to-self/measure-listen-backlog.py +++ b/notes-to-self/measure-listen-backlog.py @@ -1,7 +1,7 @@ import trio -async def run_test(nominal_backlog): +async def run_test(nominal_backlog) -> None: print("--\nnominal:", nominal_backlog) listen_sock = trio.socket.socket() diff --git a/notes-to-self/ntp-example.py b/notes-to-self/ntp-example.py index 2bb9f80fb..79b8cd0a5 100644 --- a/notes-to-self/ntp-example.py +++ b/notes-to-self/ntp-example.py @@ -53,7 +53,7 @@ def extract_transmit_timestamp(ntp_packet): return base_time + offset -async def main(): +async def main() -> None: print("Our clock currently reads (in UTC):", datetime.datetime.utcnow()) # Look up some random NTP servers. diff --git a/notes-to-self/print-task-tree.py b/notes-to-self/print-task-tree.py index 54b97ec01..5f9c535b0 100644 --- a/notes-to-self/print-task-tree.py +++ b/notes-to-self/print-task-tree.py @@ -78,7 +78,7 @@ def task_tree_lines(task=None): return _render_subtree(task.name, rendered_children) -def print_task_tree(task=None): +def print_task_tree(task=None) -> None: for line in task_tree_lines(task): print(line) @@ -86,20 +86,20 @@ def print_task_tree(task=None): ################################################################ -async def child2(): +async def child2() -> None: async with trio.open_nursery() as nursery: nursery.start_soon(trio.sleep_forever) nursery.start_soon(trio.sleep_forever) -async def child1(): +async def child1() -> None: async with trio.open_nursery() as nursery: nursery.start_soon(child2) nursery.start_soon(child2) nursery.start_soon(trio.sleep_forever) -async def main(): +async def main() -> None: async with trio.open_nursery() as nursery0: nursery0.start_soon(child1) async with trio.open_nursery() as nursery1: diff --git a/notes-to-self/proxy-benchmarks.py b/notes-to-self/proxy-benchmarks.py index 830327cf4..85d7db1c0 100644 --- a/notes-to-self/proxy-benchmarks.py +++ b/notes-to-self/proxy-benchmarks.py @@ -8,7 +8,7 @@ class Proxy1: strategy = "__getattr__" works_for = "any attr" - def __init__(self, wrapped): + def __init__(self, wrapped) -> None: self._wrapped = wrapped def __getattr__(self, name): @@ -24,11 +24,11 @@ class Proxy2: strategy = "generated methods (getattr + closure)" works_for = "methods" - def __init__(self, wrapped): + def __init__(self, wrapped) -> None: self._wrapped = wrapped -def add_wrapper(cls, method): +def add_wrapper(cls, method) -> None: def wrapper(self, *args, **kwargs): return getattr(self._wrapped, method)(*args, **kwargs) @@ -45,11 +45,11 @@ class Proxy3: strategy = "generated methods (exec)" works_for = "methods" - def __init__(self, wrapped): + def __init__(self, wrapped) -> None: self._wrapped = wrapped -def add_wrapper(cls, method): +def add_wrapper(cls, method) -> None: code = textwrap.dedent( f""" def wrapper(self, *args, **kwargs): @@ -71,18 +71,18 @@ class Proxy4: strategy = "generated properties (getattr + closure)" works_for = "any attr" - def __init__(self, wrapped): + def __init__(self, wrapped) -> None: self._wrapped = wrapped -def add_wrapper(cls, attr): +def add_wrapper(cls, attr) -> None: def getter(self): return getattr(self._wrapped, attr) - def setter(self, newval): + def setter(self, newval) -> None: setattr(self._wrapped, attr, newval) - def deleter(self): + def deleter(self) -> None: delattr(self._wrapped, attr) setattr(cls, attr, property(getter, setter, deleter)) @@ -98,11 +98,11 @@ class Proxy5: strategy = "generated properties (exec)" works_for = "any attr" - def __init__(self, wrapped): + def __init__(self, wrapped) -> None: self._wrapped = wrapped -def add_wrapper(cls, attr): +def add_wrapper(cls, attr) -> None: code = textwrap.dedent( f""" def getter(self): @@ -131,7 +131,7 @@ class Proxy6: strategy = "copy attrs from wrappee to wrapper" works_for = "methods + constant attrs" - def __init__(self, wrapper): + def __init__(self, wrapper) -> None: self._wrapper = wrapper for method in methods: @@ -143,7 +143,7 @@ def __init__(self, wrapper): classes = [Proxy1, Proxy2, Proxy3, Proxy4, Proxy5, Proxy6] -def check(cls): +def check(cls) -> None: with open("/etc/passwd") as f: p = cls(f) assert p.fileno() == f.fileno() diff --git a/notes-to-self/reopen-pipe.py b/notes-to-self/reopen-pipe.py index dbccd567d..679c854ef 100644 --- a/notes-to-self/reopen-pipe.py +++ b/notes-to-self/reopen-pipe.py @@ -4,7 +4,7 @@ import time -def check_reopen(r1, w): +def check_reopen(r1, w) -> None: try: print("Reopening read end") r2 = os.open(f"/proc/self/fd/{r1}", os.O_RDONLY) @@ -34,7 +34,7 @@ def check_reopen(r1, w): print("r2 definitely seems to be in non-blocking mode") # Check that r1 is really truly still in blocking mode - def sleep_then_write(): + def sleep_then_write() -> None: time.sleep(1) os.write(w, b"c") diff --git a/notes-to-self/schedule-timing.py b/notes-to-self/schedule-timing.py index 11594b7cc..4fa88aeaf 100644 --- a/notes-to-self/schedule-timing.py +++ b/notes-to-self/schedule-timing.py @@ -6,7 +6,7 @@ RUNNING = True -async def reschedule_loop(depth): +async def reschedule_loop(depth) -> None: if depth == 0: global LOOPS while RUNNING: @@ -17,7 +17,7 @@ async def reschedule_loop(depth): await reschedule_loop(depth - 1) -async def report_loop(): +async def report_loop() -> None: global RUNNING try: while True: @@ -33,7 +33,7 @@ async def report_loop(): RUNNING = False -async def main(): +async def main() -> None: async with trio.open_nursery() as nursery: nursery.start_soon(reschedule_loop, 10) nursery.start_soon(report_loop) diff --git a/notes-to-self/socket-scaling.py b/notes-to-self/socket-scaling.py index bd7e32ef7..3d9199440 100644 --- a/notes-to-self/socket-scaling.py +++ b/notes-to-self/socket-scaling.py @@ -24,10 +24,10 @@ import trio.testing -async def main(): +async def main() -> None: for total in [10, 100, 500, 1_000, 10_000, 20_000, 30_000]: - def pt(desc, *, count=total, item="socket"): + def pt(desc, *, count=total, item="socket") -> None: nonlocal last_time now = time.perf_counter() total_ms = (now - last_time) * 1000 diff --git a/notes-to-self/ssl-close-notify/ssl-close-notify.py b/notes-to-self/ssl-close-notify/ssl-close-notify.py index 7a55b8c99..8df8cbb42 100644 --- a/notes-to-self/ssl-close-notify/ssl-close-notify.py +++ b/notes-to-self/ssl-close-notify/ssl-close-notify.py @@ -23,7 +23,7 @@ client_done = threading.Event() -def server_thread_fn(): +def server_thread_fn() -> None: server_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) server_ctx.load_cert_chain("trio-test-1.pem") server = server_ctx.wrap_socket( diff --git a/notes-to-self/ssl-handshake/ssl-handshake.py b/notes-to-self/ssl-handshake/ssl-handshake.py index 1665ce333..6b73339c8 100644 --- a/notes-to-self/ssl-handshake/ssl-handshake.py +++ b/notes-to-self/ssl-handshake/ssl-handshake.py @@ -9,7 +9,7 @@ server_ctx.load_cert_chain("trio-test-1.pem") -def _ssl_echo_serve_sync(sock): +def _ssl_echo_serve_sync(sock) -> None: try: wrapped = server_ctx.wrap_socket(sock, server_side=True) while True: @@ -37,7 +37,7 @@ def echo_server_connection(): class ManuallyWrappedSocket: - def __init__(self, ctx, sock, **kwargs): + def __init__(self, ctx, sock, **kwargs) -> None: self.incoming = ssl.MemoryBIO() self.outgoing = ssl.MemoryBIO() self.obj = ctx.wrap_bio(self.incoming, self.outgoing, **kwargs) @@ -71,13 +71,13 @@ def _retry(self, fn, *args): # then retry if necessary return ret - def do_handshake(self): + def do_handshake(self) -> None: self._retry(self.obj.do_handshake) def recv(self, bufsize): return self._retry(self.obj.read, bufsize) - def sendall(self, data): + def sendall(self, data) -> None: self._retry(self.obj.write, data) def unwrap(self): diff --git a/notes-to-self/thread-closure-bug-demo.py b/notes-to-self/thread-closure-bug-demo.py index b5da68c33..6985534bd 100644 --- a/notes-to-self/thread-closure-bug-demo.py +++ b/notes-to-self/thread-closure-bug-demo.py @@ -23,7 +23,7 @@ def run_with_slow_tracefunc(fn): return fn() -def outer(): +def outer() -> None: x = 0 # We hide the done variable inside a list, because we want to use it to # communicate between the main thread and the looper thread, and the bug diff --git a/notes-to-self/thread-dispatch-bench.py b/notes-to-self/thread-dispatch-bench.py index 70547a600..427cc0a62 100644 --- a/notes-to-self/thread-dispatch-bench.py +++ b/notes-to-self/thread-dispatch-bench.py @@ -11,13 +11,13 @@ COUNT = 10000 -def worker(in_q, out_q): +def worker(in_q, out_q) -> None: while True: job = in_q.get() out_q.put(job()) -def main(): +def main() -> None: in_q = Queue() out_q = Queue() diff --git a/notes-to-self/time-wait.py b/notes-to-self/time-wait.py index edc1b3917..a2a7dd165 100644 --- a/notes-to-self/time-wait.py +++ b/notes-to-self/time-wait.py @@ -40,7 +40,7 @@ class Options: server = None listen2 = None - def set(self, which, sock): + def set(self, which, sock) -> None: value = getattr(self, which) if value is not None: sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, value) @@ -54,7 +54,7 @@ def describe(self): return "Set/unset: {}".format(", ".join(info)) -def time_wait(options): +def time_wait(options) -> None: print(options.describe()) # Find a pristine port (one we can definitely bind to without diff --git a/notes-to-self/trace.py b/notes-to-self/trace.py index 046412d3a..3294ce431 100644 --- a/notes-to-self/trace.py +++ b/notes-to-self/trace.py @@ -32,20 +32,20 @@ class Trace(trio.abc.Instrument): - def __init__(self, out): + def __init__(self, out) -> None: self.out = out self.out.write("[\n") self.ids = count() self._task_metadata(-1, "I/O manager") - def _write(self, **ev): + def _write(self, **ev) -> None: ev.setdefault("pid", os.getpid()) if ev["ph"] != "M": ev.setdefault("ts", trio.current_time() * 1e6) self.out.write(json.dumps(ev)) self.out.write(",\n") - def _task_metadata(self, tid, name): + def _task_metadata(self, tid, name) -> None: self._write( name="thread_name", ph="M", @@ -59,7 +59,7 @@ def _task_metadata(self, tid, name): args={"sort_index": tid}, ) - def task_spawned(self, task): + def task_spawned(self, task) -> None: self._task_metadata(task._counter, task.name) self._write( name="task lifetime", @@ -67,28 +67,28 @@ def task_spawned(self, task): tid=task._counter, ) - def task_exited(self, task): + def task_exited(self, task) -> None: self._write( name="task lifetime", ph="E", tid=task._counter, ) - def before_task_step(self, task): + def before_task_step(self, task) -> None: self._write( name="running", ph="B", tid=task._counter, ) - def after_task_step(self, task): + def after_task_step(self, task) -> None: self._write( name="running", ph="E", tid=task._counter, ) - def task_scheduled(self, task): + def task_scheduled(self, task) -> None: try: waker = trio.lowlevel.current_task() except RuntimeError: @@ -108,14 +108,14 @@ def task_scheduled(self, task): tid=task._counter, ) - def before_io_wait(self, timeout): + def before_io_wait(self, timeout) -> None: self._write( name="I/O wait", ph="B", tid=-1, ) - def after_io_wait(self, timeout): + def after_io_wait(self, timeout) -> None: self._write( name="I/O wait", ph="E", @@ -123,19 +123,19 @@ def after_io_wait(self, timeout): ) -async def child1(): +async def child1() -> None: print(" child1: started! sleeping now...") await trio.sleep(1) print(" child1: exiting!") -async def child2(): +async def child2() -> None: print(" child2: started! sleeping now...") await trio.sleep(1) print(" child2: exiting!") -async def parent(): +async def parent() -> None: print("parent: started!") async with trio.open_nursery() as nursery: print("parent: spawning child1...") diff --git a/notes-to-self/trivial-err.py b/notes-to-self/trivial-err.py index 6c32617c7..1b0b7adde 100644 --- a/notes-to-self/trivial-err.py +++ b/notes-to-self/trivial-err.py @@ -1,29 +1,30 @@ import sys +from typing import NoReturn import trio sys.stderr = sys.stdout -async def child1(): +async def child1() -> NoReturn: raise ValueError -async def child2(): +async def child2() -> None: async with trio.open_nursery() as nursery: nursery.start_soon(grandchild1) nursery.start_soon(grandchild2) -async def grandchild1(): +async def grandchild1() -> NoReturn: raise KeyError -async def grandchild2(): +async def grandchild2() -> NoReturn: raise NameError("Bob") -async def main(): +async def main() -> None: async with trio.open_nursery() as nursery: nursery.start_soon(child1) nursery.start_soon(child2) diff --git a/notes-to-self/trivial.py b/notes-to-self/trivial.py index 405d92daf..f02d5a297 100644 --- a/notes-to-self/trivial.py +++ b/notes-to-self/trivial.py @@ -1,7 +1,7 @@ import trio -async def foo(): +async def foo() -> int: print("in foo!") return 3 diff --git a/notes-to-self/wakeup-fd-racer.py b/notes-to-self/wakeup-fd-racer.py index 97faa0dfd..a48384942 100644 --- a/notes-to-self/wakeup-fd-racer.py +++ b/notes-to-self/wakeup-fd-racer.py @@ -16,13 +16,13 @@ signal_raise = getattr(_lib, "raise") else: - def signal_raise(signum): + def signal_raise(signum) -> None: # Use pthread_kill to make sure we're actually using the wakeup fd on # Unix signal.pthread_kill(threading.get_ident(), signum) -def raise_SIGINT_soon(): +def raise_SIGINT_soon() -> None: time.sleep(1) signal_raise(signal.SIGINT) # Sending 2 signals becomes reliable, as we'd expect (because we need @@ -41,7 +41,7 @@ def drain(sock): return total -def main(): +def main() -> None: writer, reader = socket.socketpair() writer.setblocking(False) reader.setblocking(False) diff --git a/notes-to-self/win-waitable-timer.py b/notes-to-self/win-waitable-timer.py index b8d9af6ca..848f8229e 100644 --- a/notes-to-self/win-waitable-timer.py +++ b/notes-to-self/win-waitable-timer.py @@ -96,7 +96,7 @@ PROCESS_LEAP_SECOND_INFO_FLAG_ENABLE_SIXTY_SECOND = 1 -def set_leap_seconds_enabled(enabled): +def set_leap_seconds_enabled(enabled) -> None: plsi = ffi.new("PROCESS_LEAP_SECOND_INFO*") if enabled: plsi.Flags = PROCESS_LEAP_SECOND_INFO_FLAG_ENABLE_SIXTY_SECOND @@ -160,7 +160,7 @@ def py_datetime_to_win_filetime(dt): return round((dt - FILETIME_EPOCH).total_seconds() * FILETIME_TICKS_PER_SECOND) -async def main(): +async def main() -> None: h = kernel32.CreateWaitableTimerW(ffi.NULL, True, ffi.NULL) if not h: raise_winerror() diff --git a/src/trio/_channel.py b/src/trio/_channel.py index 8a7dba140..91a8c0811 100644 --- a/src/trio/_channel.py +++ b/src/trio/_channel.py @@ -101,7 +101,7 @@ def __new__( # type: ignore[misc] # "must return a subtype" ) -> tuple[MemorySendChannel[T], MemoryReceiveChannel[T]]: return _open_memory_channel(max_buffer_size) - def __init__(self, max_buffer_size: int | float): # noqa: PYI041 + def __init__(self, max_buffer_size: int | float) -> None: # noqa: PYI041 ... else: diff --git a/src/trio/_core/_instrumentation.py b/src/trio/_core/_instrumentation.py index c1063b0e3..9bcc69bc3 100644 --- a/src/trio/_core/_instrumentation.py +++ b/src/trio/_core/_instrumentation.py @@ -29,7 +29,7 @@ class Instruments(Dict[str, Dict[Instrument, None]]): __slots__ = () - def __init__(self, incoming: Sequence[Instrument]): + def __init__(self, incoming: Sequence[Instrument]) -> None: self["_all"] = {} for instrument in incoming: self.add_instrument(instrument) diff --git a/src/trio/_core/_mock_clock.py b/src/trio/_core/_mock_clock.py index 70c4e58a2..7e85df2f7 100644 --- a/src/trio/_core/_mock_clock.py +++ b/src/trio/_core/_mock_clock.py @@ -63,7 +63,7 @@ class MockClock(Clock): """ - def __init__(self, rate: float = 0.0, autojump_threshold: float = inf): + def __init__(self, rate: float = 0.0, autojump_threshold: float = inf) -> None: # when the real clock said 'real_base', the virtual time was # 'virtual_base', and since then it's advanced at 'rate' virtual # seconds per real second. diff --git a/src/trio/_core/_run.py b/src/trio/_core/_run.py index 5de75e8e6..3d8b9b629 100644 --- a/src/trio/_core/_run.py +++ b/src/trio/_core/_run.py @@ -1128,7 +1128,7 @@ def __init__( parent_task: Task, cancel_scope: CancelScope, strict_exception_groups: bool, - ): + ) -> None: self._parent_task = parent_task self._strict_exception_groups = strict_exception_groups parent_task._child_nurseries.append(self) diff --git a/src/trio/_dtls.py b/src/trio/_dtls.py index 62b01292a..18b228589 100644 --- a/src/trio/_dtls.py +++ b/src/trio/_dtls.py @@ -669,7 +669,7 @@ def challenge_for( class _Queue(Generic[_T]): - def __init__(self, incoming_packets_buffer: int | float): # noqa: PYI041 + def __init__(self, incoming_packets_buffer: int | float) -> None: # noqa: PYI041 self.s, self.r = trio.open_memory_channel[_T](incoming_packets_buffer) diff --git a/src/trio/_highlevel_socket.py b/src/trio/_highlevel_socket.py index 8d9e76807..c04e66e1b 100644 --- a/src/trio/_highlevel_socket.py +++ b/src/trio/_highlevel_socket.py @@ -68,7 +68,7 @@ class SocketStream(HalfCloseableStream): """ - def __init__(self, socket: SocketType): + def __init__(self, socket: SocketType) -> None: if not isinstance(socket, tsocket.SocketType): raise TypeError("SocketStream requires a Trio socket object") if socket.type != tsocket.SOCK_STREAM: @@ -364,7 +364,7 @@ class SocketListener(Listener[SocketStream]): """ - def __init__(self, socket: SocketType): + def __init__(self, socket: SocketType) -> None: if not isinstance(socket, tsocket.SocketType): raise TypeError("SocketListener requires a Trio socket object") if socket.type != tsocket.SOCK_STREAM: diff --git a/src/trio/_repl.py b/src/trio/_repl.py index 73f050140..f9efcc001 100644 --- a/src/trio/_repl.py +++ b/src/trio/_repl.py @@ -22,7 +22,7 @@ class TrioInteractiveConsole(InteractiveConsole): # we make the type more specific on our subclass locals: dict[str, object] - def __init__(self, repl_locals: dict[str, object] | None = None): + def __init__(self, repl_locals: dict[str, object] | None = None) -> None: super().__init__(locals=repl_locals) self.compile.compiler.flags |= ast.PyCF_ALLOW_TOP_LEVEL_AWAIT diff --git a/src/trio/_socket.py b/src/trio/_socket.py index 6dbe9c0c4..42d622951 100644 --- a/src/trio/_socket.py +++ b/src/trio/_socket.py @@ -64,7 +64,7 @@ class _try_sync: def __init__( self, blocking_exc_override: Callable[[BaseException], bool] | None = None, - ): + ) -> None: self._blocking_exc_override = blocking_exc_override def _is_blocking_io_error(self, exc: BaseException) -> bool: @@ -781,7 +781,7 @@ async def sendmsg( class _SocketType(SocketType): - def __init__(self, sock: _stdlib_socket.socket): + def __init__(self, sock: _stdlib_socket.socket) -> None: if type(sock) is not _stdlib_socket.socket: # For example, ssl.SSLSocket subclasses socket.socket, but we # certainly don't want to blindly wrap one of those. diff --git a/src/trio/_sync.py b/src/trio/_sync.py index 698716ea3..60fd18302 100644 --- a/src/trio/_sync.py +++ b/src/trio/_sync.py @@ -213,7 +213,7 @@ class CapacityLimiter(AsyncContextManagerMixin): """ # total_tokens would ideally be int|Literal[math.inf] - but that's not valid typing - def __init__(self, total_tokens: int | float): # noqa: PYI041 + def __init__(self, total_tokens: int | float) -> None: # noqa: PYI041 self._lot = ParkingLot() self._borrowers: set[Task | object] = set() # Maps tasks attempting to acquire -> borrower, to handle on-behalf-of @@ -426,7 +426,7 @@ class Semaphore(AsyncContextManagerMixin): """ - def __init__(self, initial_value: int, *, max_value: int | None = None): + def __init__(self, initial_value: int, *, max_value: int | None = None) -> None: if not isinstance(initial_value, int): raise TypeError("initial_value must be an int") if initial_value < 0: @@ -740,7 +740,7 @@ class Condition(AsyncContextManagerMixin): """ - def __init__(self, lock: Lock | None = None): + def __init__(self, lock: Lock | None = None) -> None: if lock is None: lock = Lock() if type(lock) is not Lock: diff --git a/src/trio/testing/_check_streams.py b/src/trio/testing/_check_streams.py index 335c9c1ea..4339163ee 100644 --- a/src/trio/testing/_check_streams.py +++ b/src/trio/testing/_check_streams.py @@ -314,7 +314,7 @@ async def expect_cancelled( # receive stream causes it to wake up. async with _ForceCloseBoth(await stream_maker()) as (s, r): - async def receive_expecting_closed(): + async def receive_expecting_closed() -> None: with _assert_raises(_core.ClosedResourceError): await r.receive_some(10) diff --git a/src/trio/testing/_fake_net.py b/src/trio/testing/_fake_net.py index ed0f6980f..20265937d 100644 --- a/src/trio/testing/_fake_net.py +++ b/src/trio/testing/_fake_net.py @@ -210,7 +210,7 @@ def __init__( family: AddressFamily, type: SocketKind, proto: int, - ): + ) -> None: self._fake_net = fake_net if not family: # pragma: no cover diff --git a/src/trio/testing/_memory_streams.py b/src/trio/testing/_memory_streams.py index 26ddde856..4183e321f 100644 --- a/src/trio/testing/_memory_streams.py +++ b/src/trio/testing/_memory_streams.py @@ -113,7 +113,7 @@ def __init__( send_all_hook: AsyncHook | None = None, wait_send_all_might_not_block_hook: AsyncHook | None = None, close_hook: SyncHook | None = None, - ): + ) -> None: self._conflict_detector = _util.ConflictDetector( "another task is using this stream", ) @@ -223,7 +223,7 @@ def __init__( self, receive_some_hook: AsyncHook | None = None, close_hook: SyncHook | None = None, - ): + ) -> None: self._conflict_detector = _util.ConflictDetector( "another task is using this stream", ) @@ -548,7 +548,7 @@ async def receive_some(self, max_bytes: int | None = None) -> bytes | bytearray: class _LockstepSendStream(SendStream): - def __init__(self, lbq: _LockstepByteQueue): + def __init__(self, lbq: _LockstepByteQueue) -> None: self._lbq = lbq def close(self) -> None: @@ -566,7 +566,7 @@ async def wait_send_all_might_not_block(self) -> None: class _LockstepReceiveStream(ReceiveStream): - def __init__(self, lbq: _LockstepByteQueue): + def __init__(self, lbq: _LockstepByteQueue) -> None: self._lbq = lbq def close(self) -> None: diff --git a/src/trio/testing/_raises_group.py b/src/trio/testing/_raises_group.py index 627663ffb..8fa308252 100644 --- a/src/trio/testing/_raises_group.py +++ b/src/trio/testing/_raises_group.py @@ -54,7 +54,7 @@ class _ExceptionInfo(Generic[MatchE]): def __init__( self, excinfo: tuple[type[MatchE], MatchE, types.TracebackType] | None, - ): + ) -> None: self._excinfo = excinfo def fill_unfilled( @@ -176,7 +176,7 @@ def __init__( exception_type: type[MatchE], match: str | Pattern[str] = ..., check: Callable[[MatchE], bool] = ..., - ): ... + ) -> None: ... @overload def __init__( @@ -185,10 +185,10 @@ def __init__( match: str | Pattern[str], # If exception_type is not provided, check() must do any typechecks itself. check: Callable[[BaseException], bool] = ..., - ): ... + ) -> None: ... @overload - def __init__(self, *, check: Callable[[BaseException], bool]): ... + def __init__(self, *, check: Callable[[BaseException], bool]) -> None: ... def __init__( self, @@ -351,7 +351,7 @@ def __init__( flatten_subgroups: bool = False, match: None = None, check: None = None, - ): ... + ) -> None: ... # flatten_subgroups = True also requires no nested RaisesGroup @overload @@ -363,7 +363,7 @@ def __init__( flatten_subgroups: Literal[True], match: str | Pattern[str] | None = None, check: Callable[[BaseExceptionGroup[E]], bool] | None = None, - ): ... + ) -> None: ... @overload def __init__( @@ -374,7 +374,7 @@ def __init__( flatten_subgroups: Literal[False] = False, match: str | Pattern[str] | None = None, check: Callable[[BaseExceptionGroup[E]], bool] | None = None, - ): ... + ) -> None: ... def __init__( self, From c05eaa68dee6ef66d974604997862e3c37ea8434 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Sun, 29 Sep 2024 02:23:49 -0500 Subject: [PATCH 03/52] Manually fix remaining new issues --- pyproject.toml | 2 + src/trio/_core/_concat_tb.py | 4 +- src/trio/_core/_instrumentation.py | 6 ++- src/trio/_core/_run.py | 4 +- src/trio/_core/_tests/test_guest_mode.py | 11 +++-- src/trio/_core/_traps.py | 10 +++-- src/trio/_dtls.py | 11 ++--- src/trio/_file_io.py | 7 ++- src/trio/_highlevel_open_tcp_stream.py | 4 +- src/trio/_socket.py | 2 +- src/trio/_ssl.py | 4 +- src/trio/_subprocess_platform/__init__.py | 8 ++-- .../test_highlevel_open_tcp_listeners.py | 6 ++- .../_tests/test_highlevel_open_tcp_stream.py | 12 ++++-- src/trio/_tests/test_highlevel_ssl_helpers.py | 7 ++- src/trio/_tests/test_socket.py | 34 +++++++++------ src/trio/_tests/test_ssl.py | 43 ++++++++++++------- src/trio/_tests/test_subprocess.py | 12 ++++-- src/trio/_tests/test_unix_pipes.py | 6 +-- src/trio/_tests/test_util.py | 20 ++++++--- src/trio/_util.py | 2 +- src/trio/testing/_fake_net.py | 2 +- 22 files changed, 143 insertions(+), 74 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 781fd8249..c54cdd490 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -154,6 +154,8 @@ extend-ignore = [ 'src/trio/lowlevel.py' = ['F401'] 'src/trio/socket.py' = ['F401'] 'src/trio/testing/__init__.py' = ['F401'] +# Don't check annotations in notes-to-self +'notes-to-self/*.py' = ['ANN'] [tool.ruff.lint.isort] combine-as-imports = true diff --git a/src/trio/_core/_concat_tb.py b/src/trio/_core/_concat_tb.py index 2ddaf2e8e..919c303e3 100644 --- a/src/trio/_core/_concat_tb.py +++ b/src/trio/_core/_concat_tb.py @@ -86,7 +86,9 @@ def copy_tb(base_tb: TracebackType, tb_next: TracebackType | None) -> TracebackT def copy_tb(base_tb: TracebackType, tb_next: TracebackType | None) -> TracebackType: # tputil.ProxyOperation is PyPy-only, and there's no way to specify # cpython/pypy in current type checkers. - def controller(operation: tputil.ProxyOperation) -> Any | None: # type: ignore[no-any-unimported] + def controller( # type: ignore[no-any-unimported] + operation: tputil.ProxyOperation, + ) -> Any | None: # noqa: ANN401 # Using Any # Rationale for pragma: I looked fairly carefully and tried a few # things, and AFAICT it's not actually possible to get any # 'opname' that isn't __getattr__ or __getattribute__. So there's diff --git a/src/trio/_core/_instrumentation.py b/src/trio/_core/_instrumentation.py index 9bcc69bc3..0139b4dea 100644 --- a/src/trio/_core/_instrumentation.py +++ b/src/trio/_core/_instrumentation.py @@ -86,7 +86,11 @@ def remove_instrument(self, instrument: Instrument) -> None: if not instruments: del self[hookname] - def call(self, hookname: str, *args: Any) -> None: + def call( + self, + hookname: str, + *args: Any, # noqa: ANN401 # Using Any + ) -> None: """Call hookname(*args) on each applicable instrument. You must first check whether there are any instruments installed for diff --git a/src/trio/_core/_run.py b/src/trio/_core/_run.py index 3d8b9b629..b81249a70 100644 --- a/src/trio/_core/_run.py +++ b/src/trio/_core/_run.py @@ -1282,7 +1282,7 @@ async def start( async_fn: Callable[..., Awaitable[object]], *args: object, name: object = None, - ) -> Any: + ) -> Any: # noqa: ANN401 # Using Any r"""Creates and initializes a child task. Like :meth:`start_soon`, but blocks until the new task has @@ -2819,7 +2819,7 @@ class _TaskStatusIgnored(TaskStatus[Any]): def __repr__(self) -> str: return "TASK_STATUS_IGNORED" - def started(self, value: Any = None) -> None: + def started(self, value: Any = None) -> None: # noqa: ANN401 # Using Any pass diff --git a/src/trio/_core/_tests/test_guest_mode.py b/src/trio/_core/_tests/test_guest_mode.py index 1a8b230e7..a6edbb13f 100644 --- a/src/trio/_core/_tests/test_guest_mode.py +++ b/src/trio/_core/_tests/test_guest_mode.py @@ -52,7 +52,7 @@ def trivial_guest_run( trio_fn: Callable[..., Awaitable[T]], *, in_host_after_start: Callable[[], None] | None = None, - **start_guest_run_kwargs: Any, + **start_guest_run_kwargs: Any, # noqa: ANN401 # Using Any, too diverse ) -> T: todo: queue.Queue[tuple[str, Outcome[T] | Callable[..., object]]] = queue.Queue() @@ -436,7 +436,7 @@ def aiotrio_run( trio_fn: Callable[..., Awaitable[T]], *, pass_not_threadsafe: bool = True, - **start_guest_run_kwargs: Any, + **start_guest_run_kwargs: Any, # noqa: ANN401 # Using Any, too diverse ) -> T: loop = asyncio.new_event_loop() @@ -557,11 +557,14 @@ async def crash_in_worker_thread_io(in_host: InHost) -> None: t = threading.current_thread() old_get_events = trio._core._run.TheIOManager.get_events - def bad_get_events(*args: Any) -> object: + def bad_get_events( + self: trio._core._run.TheIOManager, + timeout: float, + ) -> trio._core._run.EventResult: if threading.current_thread() is not t: raise ValueError("oh no!") else: - return old_get_events(*args) + return old_get_events(self, timeout) m.setattr("trio._core._run.TheIOManager.get_events", bad_get_events) diff --git a/src/trio/_core/_traps.py b/src/trio/_core/_traps.py index 27518406c..9222c2f10 100644 --- a/src/trio/_core/_traps.py +++ b/src/trio/_core/_traps.py @@ -25,7 +25,7 @@ # tracking machinery. Since our traps are public APIs, we make them real async # functions, and then this helper takes care of the actual yield: @types.coroutine -def _async_yield(obj: Any) -> Any: # type: ignore[misc] +def _async_yield(obj: Any) -> Any: # type: ignore[misc] # noqa: ANN401 return (yield obj) @@ -77,7 +77,9 @@ class WaitTaskRescheduled: # Should always return the type a Task "expects", unless you willfully reschedule it # with a bad value. -async def wait_task_rescheduled(abort_func: Callable[[RaiseCancelT], Abort]) -> Any: +async def wait_task_rescheduled( + abort_func: Callable[[RaiseCancelT], Abort], +) -> Any: # noqa: ANN401 # Any used """Put the current task to sleep, with cancellation support. This is the lowest-level API for blocking in Trio. Every time a @@ -187,7 +189,7 @@ class PermanentlyDetachCoroutineObject: async def permanently_detach_coroutine_object( final_outcome: outcome.Outcome[Any], -) -> Any: +) -> Any: # noqa: ANN401 # Any used """Permanently detach the current task from the Trio scheduler. Normally, a Trio task doesn't exit until its coroutine object exits. When @@ -220,7 +222,7 @@ async def permanently_detach_coroutine_object( async def temporarily_detach_coroutine_object( abort_func: Callable[[RaiseCancelT], Abort], -) -> Any: +) -> Any: # noqa: ANN401 # Any used """Temporarily detach the current coroutine object from the Trio scheduler. diff --git a/src/trio/_dtls.py b/src/trio/_dtls.py index 18b228589..decf9bd4a 100644 --- a/src/trio/_dtls.py +++ b/src/trio/_dtls.py @@ -43,6 +43,7 @@ from OpenSSL import SSL # noqa: TCH004 from typing_extensions import Self, TypeAlias, TypeVarTuple, Unpack + from trio._socket import AddressFormat from trio.socket import SocketType PosArgsT = TypeVarTuple("PosArgsT") @@ -572,7 +573,7 @@ def _make_cookie( key: bytes, salt: bytes, tick: int, - address: Any, + address: AddressFormat, client_hello_bits: bytes, ) -> bytes: assert len(salt) == SALT_BYTES @@ -593,7 +594,7 @@ def _make_cookie( def valid_cookie( key: bytes, cookie: bytes, - address: Any, + address: AddressFormat, client_hello_bits: bytes, ) -> bool: if len(cookie) > SALT_BYTES: @@ -622,7 +623,7 @@ def valid_cookie( def challenge_for( key: bytes, - address: Any, + address: AddressFormat, epoch_seqno: int, client_hello_bits: bytes, ) -> bytes: @@ -686,7 +687,7 @@ def _read_loop(read_fn: Callable[[int], bytes]) -> bytes: async def handle_client_hello_untrusted( endpoint: DTLSEndpoint, - address: Any, + address: AddressFormat, packet: bytes, ) -> None: # it's trivial to write a simple function that directly calls this to @@ -864,7 +865,7 @@ class DTLSChannel(trio.abc.Channel[bytes], metaclass=NoPublicConstructor): def __init__( self, endpoint: DTLSEndpoint, - peer_address: Any, + peer_address: AddressFormat, ctx: SSL.Context, ) -> None: self.endpoint = endpoint diff --git a/src/trio/_file_io.py b/src/trio/_file_io.py index 8038ff623..f2d07394c 100644 --- a/src/trio/_file_io.py +++ b/src/trio/_file_io.py @@ -32,6 +32,8 @@ ) from typing_extensions import Literal + from ._sync import CapacityLimiter + # This list is also in the docs, make sure to keep them in sync _FILE_SYNC_ATTRS: set[str] = { "closed", @@ -242,7 +244,10 @@ def __getattr__(self, name: str) -> object: meth = getattr(self._wrapped, name) @async_wraps(self.__class__, self._wrapped.__class__, name) - async def wrapper(*args, **kwargs): + async def wrapper( + *args: Callable[..., T], + **kwargs: object | str | bool | CapacityLimiter | None, + ) -> T: func = partial(meth, *args, **kwargs) return await trio.to_thread.run_sync(func) diff --git a/src/trio/_highlevel_open_tcp_stream.py b/src/trio/_highlevel_open_tcp_stream.py index 1e7f4332d..b7c0468e0 100644 --- a/src/trio/_highlevel_open_tcp_stream.py +++ b/src/trio/_highlevel_open_tcp_stream.py @@ -11,6 +11,8 @@ from collections.abc import Generator from socket import AddressFamily, SocketKind + from trio._socket import AddressFormat + if sys.version_info < (3, 11): from exceptiongroup import BaseExceptionGroup, ExceptionGroup @@ -302,7 +304,7 @@ async def open_tcp_stream( # face of crash or cancellation async def attempt_connect( socket_args: tuple[AddressFamily, SocketKind, int], - sockaddr: Any, + sockaddr: AddressFormat, attempt_failed: trio.Event, ) -> None: nonlocal winning_socket diff --git a/src/trio/_socket.py b/src/trio/_socket.py index 42d622951..30e9071ad 100644 --- a/src/trio/_socket.py +++ b/src/trio/_socket.py @@ -476,7 +476,7 @@ async def _resolve_address_nocp( ipv6_v6only: bool | int, address: AddressFormat, local: bool, -) -> Any: +) -> AddressFormat: # Do some pre-checking (or exit early for non-IP sockets) if family == _stdlib_socket.AF_INET: if not isinstance(address, tuple) or not len(address) == 2: diff --git a/src/trio/_ssl.py b/src/trio/_ssl.py index df1cbc37b..d778a5546 100644 --- a/src/trio/_ssl.py +++ b/src/trio/_ssl.py @@ -4,7 +4,7 @@ import operator as _operator import ssl as _stdlib_ssl from enum import Enum as _Enum -from typing import TYPE_CHECKING, Any, ClassVar, Final as TFinal, Generic, TypeVar +from typing import TYPE_CHECKING, ClassVar, Final as TFinal, Generic, TypeVar import trio @@ -413,7 +413,7 @@ def __init__( "version", } - def __getattr__(self, name: str) -> Any: + def __getattr__(self, name: str) -> object: if name in self._forwarded: if name in self._after_handshake and not self._handshook.done: raise NeedHandshakeError(f"call do_handshake() before calling {name!r}") diff --git a/src/trio/_subprocess_platform/__init__.py b/src/trio/_subprocess_platform/__init__.py index d74cd462a..9a5e4d1da 100644 --- a/src/trio/_subprocess_platform/__init__.py +++ b/src/trio/_subprocess_platform/__init__.py @@ -85,11 +85,11 @@ def create_pipe_from_child_output() -> tuple[ClosableReceiveStream, int]: elif os.name == "posix": - def create_pipe_to_child_stdin(): + def create_pipe_to_child_stdin() -> tuple[trio.lowlevel.FdStream, int]: rfd, wfd = os.pipe() return trio.lowlevel.FdStream(wfd), rfd - def create_pipe_from_child_output(): + def create_pipe_from_child_output() -> tuple[trio.lowlevel.FdStream, int]: rfd, wfd = os.pipe() return trio.lowlevel.FdStream(rfd), wfd @@ -106,12 +106,12 @@ def create_pipe_from_child_output(): from .._windows_pipes import PipeReceiveStream, PipeSendStream - def create_pipe_to_child_stdin(): + def create_pipe_to_child_stdin() -> tuple[PipeSendStream, int]: # for stdin, we want the write end (our end) to use overlapped I/O rh, wh = windows_pipe(overlapped=(False, True)) return PipeSendStream(wh), msvcrt.open_osfhandle(rh, os.O_RDONLY) - def create_pipe_from_child_output(): + def create_pipe_from_child_output() -> tuple[PipeReceiveStream, int]: # for stdout/err, it's the read end that's overlapped rh, wh = windows_pipe(overlapped=(True, False)) return PipeReceiveStream(rh), msvcrt.open_osfhandle(wh, 0) diff --git a/src/trio/_tests/test_highlevel_open_tcp_listeners.py b/src/trio/_tests/test_highlevel_open_tcp_listeners.py index 6e2abf112..b041fb4ee 100644 --- a/src/trio/_tests/test_highlevel_open_tcp_listeners.py +++ b/src/trio/_tests/test_highlevel_open_tcp_listeners.py @@ -4,7 +4,7 @@ import socket as stdlib_socket import sys from socket import AddressFamily, SocketKind -from typing import TYPE_CHECKING, Any, Sequence, overload +from typing import TYPE_CHECKING, Sequence, overload import attrs import pytest @@ -28,6 +28,8 @@ if TYPE_CHECKING: from typing_extensions import Buffer + from .._socket import AddressFormat + async def test_open_tcp_listeners_basic() -> None: listeners = await open_tcp_listeners(0) @@ -193,7 +195,7 @@ def setsockopt( ) -> None: pass - async def bind(self, address: Any) -> None: + async def bind(self, address: AddressFormat) -> None: pass def listen(self, /, backlog: int = min(stdlib_socket.SOMAXCONN, 128)) -> None: diff --git a/src/trio/_tests/test_highlevel_open_tcp_stream.py b/src/trio/_tests/test_highlevel_open_tcp_stream.py index 81d2b403b..1f9bd5295 100644 --- a/src/trio/_tests/test_highlevel_open_tcp_stream.py +++ b/src/trio/_tests/test_highlevel_open_tcp_stream.py @@ -3,7 +3,7 @@ import socket import sys from socket import AddressFamily, SocketKind -from typing import TYPE_CHECKING, Any, Sequence +from typing import TYPE_CHECKING import attrs import pytest @@ -19,6 +19,8 @@ from trio.testing import Matcher, RaisesGroup if TYPE_CHECKING: + from collections.abc import Sequence + from trio.testing import MockClock if sys.version_info < (3, 11): @@ -358,7 +360,7 @@ async def run_scenario( # If this is True, we require there to be an exception, and return # (exception, scenario object) expect_error: tuple[type[BaseException], ...] | type[BaseException] = (), - **kwargs: Any, + **kwargs: str | float | None, ) -> tuple[SocketType, Scenario] | tuple[BaseException, Scenario]: supported_families = set() if ipv4_supported: @@ -370,7 +372,11 @@ async def run_scenario( trio.socket.set_custom_socket_factory(scenario) try: - stream = await open_tcp_stream("test.example.com", port, **kwargs) + stream = await open_tcp_stream( + "test.example.com", + port, + **kwargs, # type: ignore[arg-type] + ) assert expect_error == () scenario.check(stream.socket) return (stream.socket, scenario) diff --git a/src/trio/_tests/test_highlevel_ssl_helpers.py b/src/trio/_tests/test_highlevel_ssl_helpers.py index ca23c333c..841232850 100644 --- a/src/trio/_tests/test_highlevel_ssl_helpers.py +++ b/src/trio/_tests/test_highlevel_ssl_helpers.py @@ -1,7 +1,7 @@ from __future__ import annotations from functools import partial -from typing import TYPE_CHECKING, Any, NoReturn +from typing import TYPE_CHECKING, NoReturn import attrs import pytest @@ -66,7 +66,10 @@ async def getaddrinfo( ]: return [(AF_INET, SOCK_STREAM, IPPROTO_TCP, "", self.sockaddr)] - async def getnameinfo(self, *args: Any) -> NoReturn: # pragma: no cover + async def getnameinfo( + self, + *args: tuple[str, int] | tuple[str, int, int, int] | int, + ) -> NoReturn: # pragma: no cover raise NotImplementedError diff --git a/src/trio/_tests/test_socket.py b/src/trio/_tests/test_socket.py index f2c2ee955..a403272b4 100644 --- a/src/trio/_tests/test_socket.py +++ b/src/trio/_tests/test_socket.py @@ -8,17 +8,19 @@ import tempfile from pathlib import Path from socket import AddressFamily, SocketKind -from typing import TYPE_CHECKING, Any, Callable, List, Tuple, Union +from typing import TYPE_CHECKING, Any, List, Tuple, Union import attrs import pytest from .. import _core, socket as tsocket from .._core._tests.tutil import binds_ipv6, creates_ipv6 -from .._socket import _NUMERIC_ONLY, SocketType, _SocketType, _try_sync +from .._socket import _NUMERIC_ONLY, AddressFormat, SocketType, _SocketType, _try_sync from ..testing import assert_checkpoints, wait_all_tasks_blocked if TYPE_CHECKING: + from collections.abc import Callable + from typing_extensions import TypeAlias from .._highlevel_socket import SocketStream @@ -47,7 +49,11 @@ def __init__(self, orig_getaddrinfo: Callable[..., GetAddrInfoResponse]) -> None self.record: list[tuple[Any, ...]] = [] # get a normalized getaddrinfo argument tuple - def _frozenbind(self, *args: Any, **kwargs: Any) -> tuple[Any, ...]: + def _frozenbind( + self, + *args: bytes | str | int | None, + **kwargs: bytes | str | int | None, + ) -> tuple[Any, ...]: sig = inspect.signature(self._orig_getaddrinfo) bound = sig.bind(*args, **kwargs) bound.apply_defaults() @@ -58,12 +64,16 @@ def _frozenbind(self, *args: Any, **kwargs: Any) -> tuple[Any, ...]: def set( self, response: GetAddrInfoResponse | str, - *args: Any, - **kwargs: Any, + *args: bytes | str | int | None, + **kwargs: bytes | str | int | None, ) -> None: self._responses[self._frozenbind(*args, **kwargs)] = response - def getaddrinfo(self, *args: Any, **kwargs: Any) -> GetAddrInfoResponse | str: + def getaddrinfo( + self, + *args: bytes | str | int | None, + **kwargs: bytes | str | int | None, + ) -> GetAddrInfoResponse | str: bound = self._frozenbind(*args, **kwargs) self.record.append(bound) if bound in self._responses: @@ -595,7 +605,7 @@ async def res( | tuple[str, str, int] | tuple[str, str, int, int] ), - ) -> Any: + ) -> AddressFormat: return await sock._resolve_address_nocp( args, local=local, # noqa: B023 # local is not bound in function definition @@ -794,7 +804,7 @@ async def test_SocketType_connect_paths() -> None: # nose -- and then swap it back out again before we hit # wait_socket_writable, which insists on a real socket. class CancelSocket(stdlib_socket.socket): - def connect(self, *args: Any, **kwargs: Any) -> None: + def connect(self, *args: AddressFormat) -> None: # accessing private method only available in _SocketType assert isinstance(sock, _SocketType) @@ -804,7 +814,7 @@ def connect(self, *args: Any, **kwargs: Any) -> None: self.family, self.type, ) - sock._sock.connect(*args, **kwargs) + sock._sock.connect(*args) # If connect *doesn't* raise, then pretend it did raise BlockingIOError # pragma: no cover @@ -851,9 +861,9 @@ async def test_resolve_address_exception_in_connect_closes_socket() -> None: with tsocket.socket() as sock: async def _resolve_address_nocp( - self: Any, - *args: Any, - **kwargs: Any, + self: _SocketType, + *args: AddressFormat, + **kwargs: bool, ) -> None: cancel_scope.cancel() await _core.checkpoint() diff --git a/src/trio/_tests/test_ssl.py b/src/trio/_tests/test_ssl.py index 7197a47cc..575e2a724 100644 --- a/src/trio/_tests/test_ssl.py +++ b/src/trio/_tests/test_ssl.py @@ -11,10 +11,6 @@ from typing import ( TYPE_CHECKING, Any, - AsyncIterator, - Awaitable, - Callable, - Iterator, NoReturn, ) @@ -56,6 +52,13 @@ ) if TYPE_CHECKING: + from collections.abc import ( + AsyncIterator, + Awaitable, + Callable, + Iterator, + ) + from typing_extensions import TypeAlias from trio._core import MockClock @@ -170,8 +173,8 @@ def ssl_echo_serve_sync( # Fixture that gives a raw socket connected to a trio-test-1 echo server # (running in a thread). Useful for testing making connections with different # SSLContexts. -@asynccontextmanager # type: ignore[misc] # decorated contains Any -async def ssl_echo_server_raw(**kwargs: Any) -> AsyncIterator[SocketStream]: +@asynccontextmanager +async def ssl_echo_server_raw(**kwargs: bool) -> AsyncIterator[SocketStream]: a, b = stdlib_socket.socketpair() async with trio.open_nursery() as nursery: # Exiting the 'with a, b' context manager closes the sockets, which @@ -188,10 +191,10 @@ async def ssl_echo_server_raw(**kwargs: Any) -> AsyncIterator[SocketStream]: # Fixture that gives a properly set up SSLStream connected to a trio-test-1 # echo server (running in a thread) -@asynccontextmanager # type: ignore[misc] # decorated contains Any +@asynccontextmanager async def ssl_echo_server( client_ctx: SSLContext, - **kwargs: Any, + **kwargs: bool, ) -> AsyncIterator[SSLStream[Stream]]: async with ssl_echo_server_raw(**kwargs) as sock: yield SSLStream(sock, client_ctx, server_hostname="trio-test-1.example.org") @@ -203,7 +206,10 @@ async def ssl_echo_server( # jakkdl: it seems to implement all the abstract methods (now), so I made it inherit # from Stream for the sake of typechecking. class PyOpenSSLEchoStream(Stream): - def __init__(self, sleeper: None = None) -> None: + def __init__( + self, + sleeper: Callable[[str], Awaitable[None]] | None = None, + ) -> None: ctx = SSL.Context(SSL.SSLv23_METHOD) # TLS 1.3 removes renegotiation support. Which is great for them, but # we still have to support versions before that, and that means we @@ -251,9 +257,10 @@ def __init__(self, sleeper: None = None) -> None: "simultaneous calls to PyOpenSSLEchoStream.receive_some", ) + self.sleeper: Callable[[str], Awaitable[None]] if sleeper is None: - async def no_op_sleeper(_: object) -> None: + async def no_op_sleeper(_: str) -> None: return self.sleeper = no_op_sleeper @@ -386,10 +393,10 @@ async def do_test( await do_test("receive_some", (1,), "receive_some", (1,)) -@contextmanager # type: ignore[misc] # decorated contains Any +@contextmanager def virtual_ssl_echo_server( client_ctx: SSLContext, - **kwargs: Any, + **kwargs: Callable[[str], Awaitable[None]] | None, ) -> Iterator[SSLStream[PyOpenSSLEchoStream]]: fakesock = PyOpenSSLEchoStream(**kwargs) yield SSLStream(fakesock, client_ctx, server_hostname="trio-test-1.example.org") @@ -425,7 +432,10 @@ def ssl_wrap_pair( MemoryStapledStream: TypeAlias = StapledStream[MemorySendStream, MemoryReceiveStream] -def ssl_memory_stream_pair(client_ctx: SSLContext, **kwargs: Any) -> tuple[ +def ssl_memory_stream_pair( + client_ctx: SSLContext, + **kwargs: dict[str, Any] | None, +) -> tuple[ SSLStream[MemoryStapledStream], SSLStream[MemoryStapledStream], ]: @@ -436,7 +446,10 @@ def ssl_memory_stream_pair(client_ctx: SSLContext, **kwargs: Any) -> tuple[ MyStapledStream: TypeAlias = StapledStream[SendStream, ReceiveStream] -def ssl_lockstep_stream_pair(client_ctx: SSLContext, **kwargs: Any) -> tuple[ +def ssl_lockstep_stream_pair( + client_ctx: SSLContext, + **kwargs: dict[str, Any] | None, +) -> tuple[ SSLStream[MyStapledStream], SSLStream[MyStapledStream], ]: @@ -1319,7 +1332,7 @@ async def test_getpeercert(client_ctx: SSLContext) -> None: async def test_SSLListener(client_ctx: SSLContext) -> None: async def setup( - **kwargs: Any, + **kwargs: bool, ) -> tuple[tsocket.SocketType, SSLListener[SocketStream], SSLStream[SocketStream]]: listen_sock = tsocket.socket() await listen_sock.bind(("127.0.0.1", 0)) diff --git a/src/trio/_tests/test_subprocess.py b/src/trio/_tests/test_subprocess.py index d65a07614..ba1834d98 100644 --- a/src/trio/_tests/test_subprocess.py +++ b/src/trio/_tests/test_subprocess.py @@ -91,7 +91,10 @@ def got_signal(proc: Process, sig: SignalType) -> bool: @asynccontextmanager # type: ignore[misc] # Any in decorator -async def open_process_then_kill(*args: Any, **kwargs: Any) -> AsyncIterator[Process]: +async def open_process_then_kill( + *args: Any, # noqa: ANN401 # Any used + **kwargs: Any, # noqa: ANN401 +) -> AsyncIterator[Process]: proc = await open_process(*args, **kwargs) try: yield proc @@ -100,8 +103,11 @@ async def open_process_then_kill(*args: Any, **kwargs: Any) -> AsyncIterator[Pro await proc.wait() -@asynccontextmanager # type: ignore[misc] # Any in decorator -async def run_process_in_nursery(*args: Any, **kwargs: Any) -> AsyncIterator[Process]: +@asynccontextmanager +async def run_process_in_nursery( + *args: object, + **kwargs: object, +) -> AsyncIterator[Process]: async with _core.open_nursery() as nursery: kwargs.setdefault("check", False) proc: Process = await nursery.start(partial(run_process, *args, **kwargs)) diff --git a/src/trio/_tests/test_unix_pipes.py b/src/trio/_tests/test_unix_pipes.py index 6f8fa6e02..74914cffa 100644 --- a/src/trio/_tests/test_unix_pipes.py +++ b/src/trio/_tests/test_unix_pipes.py @@ -30,7 +30,7 @@ async def make_pipe() -> tuple[FdStream, FdStream]: return FdStream(w), FdStream(r) -async def make_clogged_pipe(): +async def make_clogged_pipe() -> tuple[FdStream, FdStream]: s, r = await make_pipe() try: while True: @@ -197,7 +197,7 @@ async def expect_closedresourceerror() -> None: orig_wait_readable = _core._run.TheIOManager.wait_readable - async def patched_wait_readable(*args, **kwargs) -> None: + async def patched_wait_readable(*args: object, **kwargs: object) -> None: await orig_wait_readable(*args, **kwargs) await r.aclose() @@ -225,7 +225,7 @@ async def expect_closedresourceerror() -> None: orig_wait_writable = _core._run.TheIOManager.wait_writable - async def patched_wait_writable(*args, **kwargs) -> None: + async def patched_wait_writable(*args: object, **kwargs: object) -> None: await orig_wait_writable(*args, **kwargs) await s.aclose() diff --git a/src/trio/_tests/test_util.py b/src/trio/_tests/test_util.py index 3e62eb622..369acec76 100644 --- a/src/trio/_tests/test_util.py +++ b/src/trio/_tests/test_util.py @@ -1,7 +1,12 @@ +from __future__ import annotations + import signal import sys import types -from typing import Any, TypeVar +from typing import TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from collections.abc import AsyncGenerator, Coroutine, Generator import pytest @@ -117,8 +122,10 @@ async def f() -> None: # pragma: no cover if sys.version_info < (3, 11): # not bothering to type this one - @asyncio.coroutine # type: ignore[misc] - def generator_based_coro() -> Any: # pragma: no cover + @asyncio.coroutine + def generator_based_coro() -> ( + Generator[Coroutine[None, None, None], None, None] + ): # pragma: no cover yield from asyncio.sleep(1) with pytest.raises(TypeError) as excinfo: @@ -147,12 +154,13 @@ def generator_based_coro() -> Any: # pragma: no cover assert "appears to be synchronous" in str(excinfo.value) - async def async_gen(_: object) -> Any: # pragma: no cover + async def async_gen( + _: object, + ) -> AsyncGenerator[None, None]: # pragma: no cover yield - # does not give arg-type typing error with pytest.raises(TypeError) as excinfo: - coroutine_or_error(async_gen, [0]) # type: ignore[unused-coroutine] + coroutine_or_error(async_gen, [0]) # type: ignore[arg-type,unused-coroutine] msg = "expected an async function but got an async generator" assert msg in str(excinfo.value) diff --git a/src/trio/_util.py b/src/trio/_util.py index 3af8b5cfd..da44c81c3 100644 --- a/src/trio/_util.py +++ b/src/trio/_util.py @@ -308,7 +308,7 @@ def __init__(self, fn: Callable[..., RetT]) -> None: update_wrapper(self, fn) self._fn = fn - def __call__(self, *args: Any, **kwargs: Any) -> RetT: + def __call__(self, *args: object, **kwargs: object) -> RetT: return self._fn(*args, **kwargs) def __getitem__(self, subscript: object) -> Self: diff --git a/src/trio/testing/_fake_net.py b/src/trio/testing/_fake_net.py index 20265937d..b83ca68da 100644 --- a/src/trio/testing/_fake_net.py +++ b/src/trio/testing/_fake_net.py @@ -313,7 +313,7 @@ async def _sendmsg( buffers: Iterable[Buffer], ancdata: Iterable[tuple[int, int, Buffer]] = (), flags: int = 0, - address: Any | None = None, + address: object | None = None, ) -> int: self._check_closed() From 9a56cb0644852f85d9692e0992d4c38b75f30e56 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Sun, 29 Sep 2024 02:36:04 -0500 Subject: [PATCH 04/52] Revert changing `__getattr__` and ignore any usage complaint --- src/trio/_ssl.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/trio/_ssl.py b/src/trio/_ssl.py index d778a5546..e5a0cdabd 100644 --- a/src/trio/_ssl.py +++ b/src/trio/_ssl.py @@ -4,7 +4,7 @@ import operator as _operator import ssl as _stdlib_ssl from enum import Enum as _Enum -from typing import TYPE_CHECKING, ClassVar, Final as TFinal, Generic, TypeVar +from typing import TYPE_CHECKING, Any, ClassVar, Final as TFinal, Generic, TypeVar import trio @@ -413,7 +413,7 @@ def __init__( "version", } - def __getattr__(self, name: str) -> object: + def __getattr__(self, name: str) -> Any: # noqa: ANN401 # Any used if name in self._forwarded: if name in self._after_handshake and not self._handshook.done: raise NeedHandshakeError(f"call do_handshake() before calling {name!r}") From a7cdba55c2b1102d7b4b813b3bbdfb15c7bc0b47 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Sun, 29 Sep 2024 02:39:44 -0500 Subject: [PATCH 05/52] Use `Any` instead of `object` --- src/trio/_tests/test_subprocess.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/trio/_tests/test_subprocess.py b/src/trio/_tests/test_subprocess.py index ba1834d98..13d6b4049 100644 --- a/src/trio/_tests/test_subprocess.py +++ b/src/trio/_tests/test_subprocess.py @@ -105,8 +105,8 @@ async def open_process_then_kill( @asynccontextmanager async def run_process_in_nursery( - *args: object, - **kwargs: object, + *args: Any, # noqa: ANN401 # Any used + **kwargs: Any, # noqa: ANN401 ) -> AsyncIterator[Process]: async with _core.open_nursery() as nursery: kwargs.setdefault("check", False) From 3c880fb316d9e8c09a0e681937e6fe4e58c0a20d Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Sun, 29 Sep 2024 02:47:38 -0500 Subject: [PATCH 06/52] Restore type ignore for decorated with `Any` --- src/trio/_tests/test_subprocess.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/trio/_tests/test_subprocess.py b/src/trio/_tests/test_subprocess.py index 13d6b4049..b0742102d 100644 --- a/src/trio/_tests/test_subprocess.py +++ b/src/trio/_tests/test_subprocess.py @@ -90,7 +90,7 @@ def got_signal(proc: Process, sig: SignalType) -> bool: return proc.returncode != 0 -@asynccontextmanager # type: ignore[misc] # Any in decorator +@asynccontextmanager # type: ignore[misc] # Any in decorated async def open_process_then_kill( *args: Any, # noqa: ANN401 # Any used **kwargs: Any, # noqa: ANN401 @@ -103,7 +103,7 @@ async def open_process_then_kill( await proc.wait() -@asynccontextmanager +@asynccontextmanager # type: ignore[misc] # Any in decorated async def run_process_in_nursery( *args: Any, # noqa: ANN401 # Any used **kwargs: Any, # noqa: ANN401 From 76538d8357d94e231c7aa4867b49c7e3a32f3b59 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Sun, 29 Sep 2024 03:09:08 -0500 Subject: [PATCH 07/52] Go into even more detail in types after looking at changes --- src/trio/_tests/test_ssl.py | 13 ++++++------- src/trio/_tests/test_subprocess.py | 4 ++-- src/trio/_tests/test_unix_pipes.py | 11 +++++++---- src/trio/testing/_fake_net.py | 4 +++- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/trio/_tests/test_ssl.py b/src/trio/_tests/test_ssl.py index 575e2a724..78a4016a6 100644 --- a/src/trio/_tests/test_ssl.py +++ b/src/trio/_tests/test_ssl.py @@ -10,7 +10,6 @@ from ssl import SSLContext from typing import ( TYPE_CHECKING, - Any, NoReturn, ) @@ -407,8 +406,8 @@ def ssl_wrap_pair( client_transport: T_Stream, server_transport: T_Stream, *, - client_kwargs: dict[str, Any] | None = None, - server_kwargs: dict[str, Any] | None = None, + client_kwargs: dict[str, str | bytes | bool | None] | None = None, + server_kwargs: dict[str, str | bytes | bool | None] | None = None, ) -> tuple[SSLStream[T_Stream], SSLStream[T_Stream]]: if server_kwargs is None: server_kwargs = {} @@ -418,13 +417,13 @@ def ssl_wrap_pair( client_transport, client_ctx, server_hostname="trio-test-1.example.org", - **client_kwargs, + **client_kwargs, # type: ignore[arg-type] ) server_ssl = SSLStream( server_transport, SERVER_CTX, server_side=True, - **server_kwargs, + **server_kwargs, # type: ignore[arg-type] ) return client_ssl, server_ssl @@ -434,7 +433,7 @@ def ssl_wrap_pair( def ssl_memory_stream_pair( client_ctx: SSLContext, - **kwargs: dict[str, Any] | None, + **kwargs: dict[str, str | bytes | bool | None] | None, ) -> tuple[ SSLStream[MemoryStapledStream], SSLStream[MemoryStapledStream], @@ -448,7 +447,7 @@ def ssl_memory_stream_pair( def ssl_lockstep_stream_pair( client_ctx: SSLContext, - **kwargs: dict[str, Any] | None, + **kwargs: dict[str, str | bytes | bool | None] | None, ) -> tuple[ SSLStream[MyStapledStream], SSLStream[MyStapledStream], diff --git a/src/trio/_tests/test_subprocess.py b/src/trio/_tests/test_subprocess.py index b0742102d..2908e2294 100644 --- a/src/trio/_tests/test_subprocess.py +++ b/src/trio/_tests/test_subprocess.py @@ -92,7 +92,7 @@ def got_signal(proc: Process, sig: SignalType) -> bool: @asynccontextmanager # type: ignore[misc] # Any in decorated async def open_process_then_kill( - *args: Any, # noqa: ANN401 # Any used + *args: Any, # noqa: ANN401 # Any used, different OS -> different args **kwargs: Any, # noqa: ANN401 ) -> AsyncIterator[Process]: proc = await open_process(*args, **kwargs) @@ -105,7 +105,7 @@ async def open_process_then_kill( @asynccontextmanager # type: ignore[misc] # Any in decorated async def run_process_in_nursery( - *args: Any, # noqa: ANN401 # Any used + *args: Any, # noqa: ANN401 # Any used, different OS -> different args **kwargs: Any, # noqa: ANN401 ) -> AsyncIterator[Process]: async with _core.open_nursery() as nursery: diff --git a/src/trio/_tests/test_unix_pipes.py b/src/trio/_tests/test_unix_pipes.py index 74914cffa..3defdda4e 100644 --- a/src/trio/_tests/test_unix_pipes.py +++ b/src/trio/_tests/test_unix_pipes.py @@ -12,6 +12,9 @@ from .._core._tests.tutil import gc_collect_harder, skip_if_fbsd_pipes_broken from ..testing import check_one_way_stream, wait_all_tasks_blocked +if TYPE_CHECKING: + from .._file_io import _HasFileNo + posix = os.name == "posix" pytestmark = pytest.mark.skipif(not posix, reason="posix only") @@ -197,8 +200,8 @@ async def expect_closedresourceerror() -> None: orig_wait_readable = _core._run.TheIOManager.wait_readable - async def patched_wait_readable(*args: object, **kwargs: object) -> None: - await orig_wait_readable(*args, **kwargs) + async def patched_wait_readable(fd: int | _HasFileNo) -> None: + await orig_wait_readable(fd) await r.aclose() monkeypatch.setattr(_core._run.TheIOManager, "wait_readable", patched_wait_readable) @@ -225,8 +228,8 @@ async def expect_closedresourceerror() -> None: orig_wait_writable = _core._run.TheIOManager.wait_writable - async def patched_wait_writable(*args: object, **kwargs: object) -> None: - await orig_wait_writable(*args, **kwargs) + async def patched_wait_writable(fd: int | _HasFileNo) -> None: + await orig_wait_writable(fd) await s.aclose() monkeypatch.setattr(_core._run.TheIOManager, "wait_writable", patched_wait_writable) diff --git a/src/trio/testing/_fake_net.py b/src/trio/testing/_fake_net.py index b83ca68da..bfe3d0ce3 100644 --- a/src/trio/testing/_fake_net.py +++ b/src/trio/testing/_fake_net.py @@ -36,6 +36,8 @@ from typing_extensions import Buffer, Self, TypeAlias + from trio._socket import AddressFormat + IPAddress: TypeAlias = Union[ipaddress.IPv4Address, ipaddress.IPv6Address] @@ -313,7 +315,7 @@ async def _sendmsg( buffers: Iterable[Buffer], ancdata: Iterable[tuple[int, int, Buffer]] = (), flags: int = 0, - address: object | None = None, + address: AddressFormat | None = None, ) -> int: self._check_closed() From 36ad52236c5168f8ee4c18ef72aaa7ae16b450bb Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Sun, 29 Sep 2024 03:17:48 -0500 Subject: [PATCH 08/52] Patched read and write need to handle `self` argument --- src/trio/_tests/test_unix_pipes.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/trio/_tests/test_unix_pipes.py b/src/trio/_tests/test_unix_pipes.py index 3defdda4e..c850ebefe 100644 --- a/src/trio/_tests/test_unix_pipes.py +++ b/src/trio/_tests/test_unix_pipes.py @@ -200,8 +200,11 @@ async def expect_closedresourceerror() -> None: orig_wait_readable = _core._run.TheIOManager.wait_readable - async def patched_wait_readable(fd: int | _HasFileNo) -> None: - await orig_wait_readable(fd) + async def patched_wait_readable( + self: _core._run.TheIOManager, + fd: int | _HasFileNo, + ) -> None: + await orig_wait_readable(self, fd) await r.aclose() monkeypatch.setattr(_core._run.TheIOManager, "wait_readable", patched_wait_readable) @@ -228,8 +231,11 @@ async def expect_closedresourceerror() -> None: orig_wait_writable = _core._run.TheIOManager.wait_writable - async def patched_wait_writable(fd: int | _HasFileNo) -> None: - await orig_wait_writable(fd) + async def patched_wait_writable( + self: _core._run.TheIOManager, + fd: int | _HasFileNo, + ) -> None: + await orig_wait_writable(self, fd) await s.aclose() monkeypatch.setattr(_core._run.TheIOManager, "wait_writable", patched_wait_writable) From 4be420bd3a341f0dfa2bfb68c8b99d9cefec250a Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:59:51 -0500 Subject: [PATCH 09/52] Remove old comment and specify exactly what issues to ignore in notes-to-self --- pyproject.toml | 2 +- src/trio/_tests/test_util.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c54cdd490..2db6ab213 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -155,7 +155,7 @@ extend-ignore = [ 'src/trio/socket.py' = ['F401'] 'src/trio/testing/__init__.py' = ['F401'] # Don't check annotations in notes-to-self -'notes-to-self/*.py' = ['ANN'] +'notes-to-self/*.py' = ['ANN001', 'ANN002', 'ANN003', 'ANN201', 'ANN202', 'ANN204'] [tool.ruff.lint.isort] combine-as-imports = true diff --git a/src/trio/_tests/test_util.py b/src/trio/_tests/test_util.py index 369acec76..e48203532 100644 --- a/src/trio/_tests/test_util.py +++ b/src/trio/_tests/test_util.py @@ -121,7 +121,7 @@ async def f() -> None: # pragma: no cover import asyncio if sys.version_info < (3, 11): - # not bothering to type this one + @asyncio.coroutine def generator_based_coro() -> ( Generator[Coroutine[None, None, None], None, None] From c4fccd0250f8d693fd757c04f022ce48e1f0eca2 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 16 Oct 2024 20:58:09 -0500 Subject: [PATCH 10/52] Address review comments Co-authored-by: John Litborn <11260241+jakkdl@users.noreply.github.com> --- src/trio/_tests/test_highlevel_open_tcp_stream.py | 3 +++ src/trio/_tests/test_ssl.py | 11 ++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/trio/_tests/test_highlevel_open_tcp_stream.py b/src/trio/_tests/test_highlevel_open_tcp_stream.py index 1f9bd5295..f05166a28 100644 --- a/src/trio/_tests/test_highlevel_open_tcp_stream.py +++ b/src/trio/_tests/test_highlevel_open_tcp_stream.py @@ -372,6 +372,9 @@ async def run_scenario( trio.socket.set_custom_socket_factory(scenario) try: + # Type ignore is for the fact that there are multiple + # keyword arguments that accept separate types, but + # str | float | None is not the same as str | None and float | None stream = await open_tcp_stream( "test.example.com", port, diff --git a/src/trio/_tests/test_ssl.py b/src/trio/_tests/test_ssl.py index 78a4016a6..3777e8392 100644 --- a/src/trio/_tests/test_ssl.py +++ b/src/trio/_tests/test_ssl.py @@ -10,6 +10,7 @@ from ssl import SSLContext from typing import ( TYPE_CHECKING, + Any, NoReturn, ) @@ -259,7 +260,7 @@ def __init__( self.sleeper: Callable[[str], Awaitable[None]] if sleeper is None: - async def no_op_sleeper(_: str) -> None: + async def no_op_sleeper(_: object) -> None: return self.sleeper = no_op_sleeper @@ -406,8 +407,8 @@ def ssl_wrap_pair( client_transport: T_Stream, server_transport: T_Stream, *, - client_kwargs: dict[str, str | bytes | bool | None] | None = None, - server_kwargs: dict[str, str | bytes | bool | None] | None = None, + client_kwargs: dict[str, Any] | None = None, + server_kwargs: dict[str, Any] | None = None, ) -> tuple[SSLStream[T_Stream], SSLStream[T_Stream]]: if server_kwargs is None: server_kwargs = {} @@ -417,13 +418,13 @@ def ssl_wrap_pair( client_transport, client_ctx, server_hostname="trio-test-1.example.org", - **client_kwargs, # type: ignore[arg-type] + **client_kwargs, ) server_ssl = SSLStream( server_transport, SERVER_CTX, server_side=True, - **server_kwargs, # type: ignore[arg-type] + **server_kwargs, ) return client_ssl, server_ssl From 12fe034374f29d03e4d4f7cd9527242a2ae158eb Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 21 Oct 2024 10:48:47 -0500 Subject: [PATCH 11/52] Revert `notes-to-self` changes --- notes-to-self/afd-lab.py | 6 ++--- notes-to-self/aio-guest-test.py | 8 +++--- notes-to-self/atomic-local.py | 2 +- notes-to-self/blocking-read-hack.py | 2 +- notes-to-self/estimate-task-size.py | 4 +-- notes-to-self/graceful-shutdown-idea.py | 8 +++--- .../how-does-windows-so-reuseaddr-work.py | 13 ++++++---- notes-to-self/loopy.py | 4 +-- notes-to-self/lots-of-tasks.py | 2 +- notes-to-self/measure-listen-backlog.py | 2 +- notes-to-self/ntp-example.py | 2 +- notes-to-self/print-task-tree.py | 8 +++--- notes-to-self/proxy-benchmarks.py | 26 +++++++++---------- notes-to-self/reopen-pipe.py | 4 +-- notes-to-self/schedule-timing.py | 6 ++--- notes-to-self/socket-scaling.py | 6 ++--- .../ssl-close-notify/ssl-close-notify.py | 2 +- notes-to-self/ssl-handshake/ssl-handshake.py | 8 +++--- notes-to-self/thread-closure-bug-demo.py | 2 +- notes-to-self/thread-dispatch-bench.py | 6 ++--- notes-to-self/time-wait.py | 4 +-- notes-to-self/trace.py | 26 +++++++++---------- notes-to-self/trivial-err.py | 11 ++++---- notes-to-self/trivial.py | 2 +- notes-to-self/wakeup-fd-racer.py | 6 ++--- notes-to-self/win-waitable-timer.py | 4 +-- 26 files changed, 88 insertions(+), 86 deletions(-) diff --git a/notes-to-self/afd-lab.py b/notes-to-self/afd-lab.py index 1a52ff17f..a95eb8bfd 100644 --- a/notes-to-self/afd-lab.py +++ b/notes-to-self/afd-lab.py @@ -99,7 +99,7 @@ class AFDLab: - def __init__(self) -> None: + def __init__(self): self._afd = _afd_helper_handle() trio.lowlevel.register_with_iocp(self._afd) @@ -141,7 +141,7 @@ async def afd_poll(self, sock, flags, *, exclusive=0): return out_flags -def fill_socket(sock) -> None: +def fill_socket(sock): try: while True: sock.send(b"x" * 65536) @@ -149,7 +149,7 @@ def fill_socket(sock) -> None: pass -async def main() -> None: +async def main(): afdlab = AFDLab() a, b = socket.socketpair() diff --git a/notes-to-self/aio-guest-test.py b/notes-to-self/aio-guest-test.py index 4995fafec..3c607d028 100644 --- a/notes-to-self/aio-guest-test.py +++ b/notes-to-self/aio-guest-test.py @@ -3,12 +3,12 @@ import trio -async def aio_main() -> None: +async def aio_main(): loop = asyncio.get_running_loop() trio_done_fut = loop.create_future() - def trio_done_callback(main_outcome) -> None: + def trio_done_callback(main_outcome): print(f"trio_main finished: {main_outcome!r}") trio_done_fut.set_result(main_outcome) @@ -21,7 +21,7 @@ def trio_done_callback(main_outcome) -> None: (await trio_done_fut).unwrap() -async def trio_main() -> None: +async def trio_main(): print("trio_main!") to_trio, from_aio = trio.open_memory_channel(float("inf")) @@ -40,7 +40,7 @@ async def trio_main() -> None: del _task_ref -async def aio_pingpong(from_trio, to_trio) -> None: +async def aio_pingpong(from_trio, to_trio): print("aio_pingpong!") while True: diff --git a/notes-to-self/atomic-local.py b/notes-to-self/atomic-local.py index b0db7ed2b..643bc16c6 100644 --- a/notes-to-self/atomic-local.py +++ b/notes-to-self/atomic-local.py @@ -4,7 +4,7 @@ sentinel = "_unique_name" -def f() -> None: +def f(): print(locals()) diff --git a/notes-to-self/blocking-read-hack.py b/notes-to-self/blocking-read-hack.py index a5d486123..688f10305 100644 --- a/notes-to-self/blocking-read-hack.py +++ b/notes-to-self/blocking-read-hack.py @@ -19,7 +19,7 @@ async def blocking_read_with_timeout( print("reading from fd", fd) cancel_requested = False - async def kill_it_after_timeout(new_fd) -> None: + async def kill_it_after_timeout(new_fd): print("sleeping") await trio.sleep(timeout) print("breaking the fd") diff --git a/notes-to-self/estimate-task-size.py b/notes-to-self/estimate-task-size.py index 7a618af7d..0010c7a2b 100644 --- a/notes-to-self/estimate-task-size.py +++ b/notes-to-self/estimate-task-size.py @@ -9,7 +9,7 @@ HIGH = 10000 -async def tinytask() -> None: +async def tinytask(): await trio.sleep_forever() @@ -22,7 +22,7 @@ async def measure(count): return resource.getrusage(resource.RUSAGE_SELF) -async def main() -> None: +async def main(): low_usage = await measure(LOW) high_usage = await measure(HIGH + LOW) diff --git a/notes-to-self/graceful-shutdown-idea.py b/notes-to-self/graceful-shutdown-idea.py index 36e9178ad..9497af972 100644 --- a/notes-to-self/graceful-shutdown-idea.py +++ b/notes-to-self/graceful-shutdown-idea.py @@ -5,11 +5,11 @@ class GracefulShutdownManager: - def __init__(self) -> None: + def __init__(self): self._shutting_down = False self._cancel_scopes = set() - def start_shutdown(self) -> None: + def start_shutdown(self): self._shutting_down = True for cancel_scope in self._cancel_scopes: cancel_scope.cancel() @@ -32,7 +32,7 @@ def shutting_down(self): # When doing operations that might block for an indefinite about of time and # that should be aborted when a graceful shutdown starts, wrap them in 'with # gsm.cancel_on_graceful_shutdown()'. -async def stream_handler(stream) -> None: +async def stream_handler(stream): while True: with gsm.cancel_on_graceful_shutdown(): data = await stream.receive_some() @@ -42,7 +42,7 @@ async def stream_handler(stream) -> None: # To trigger the shutdown: -async def listen_for_shutdown_signals() -> None: +async def listen_for_shutdown_signals(): with trio.open_signal_receiver(signal.SIGINT, signal.SIGTERM) as signal_aiter: async for _sig in signal_aiter: gsm.start_shutdown() 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 cb6264844..117b9738e 100644 --- a/notes-to-self/how-does-windows-so-reuseaddr-work.py +++ b/notes-to-self/how-does-windows-so-reuseaddr-work.py @@ -20,7 +20,7 @@ def sock(mode): return s -def bind(sock, bind_type) -> None: +def bind(sock, bind_type): if bind_type == "wildcard": sock.bind(("0.0.0.0", 12345)) elif bind_type == "specific": @@ -29,7 +29,7 @@ def bind(sock, bind_type) -> None: raise AssertionError() -def table_entry(mode1, bind_type1, mode2, bind_type2) -> str: +def table_entry(mode1, bind_type1, mode2, bind_type2): with sock(mode1) as sock1: bind(sock1, bind_type1) try: @@ -49,12 +49,15 @@ def table_entry(mode1, bind_type1, mode2, bind_type2) -> str: """ second bind | """ - + " | ".join(["%-19s" % mode for mode in modes]), + + " | ".join(f"{mode:<19}" for mode in modes), ) print(""" """, end="") for _ in modes: - print(" | " + " | ".join(["%8s" % bind_type for bind_type in bind_types]), end="") + print( + " | " + " | ".join(f"{bind_type:>8}" for bind_type in bind_types), + end="", + ) print( """ @@ -72,5 +75,5 @@ def table_entry(mode1, bind_type1, mode2, bind_type2) -> str: # print(mode1, bind_type1, mode2, bind_type2, entry) print( f"{mode1:>19} | {bind_type1:>8} | " - + " | ".join(["%8s" % entry for entry in row]), + + " | ".join(f"{entry:>8}" for entry in row), ) diff --git a/notes-to-self/loopy.py b/notes-to-self/loopy.py index e6065bbf7..99f6e050b 100644 --- a/notes-to-self/loopy.py +++ b/notes-to-self/loopy.py @@ -3,7 +3,7 @@ import trio -async def loopy() -> None: +async def loopy(): try: while True: # synchronous sleep to avoid maxing out CPU @@ -13,7 +13,7 @@ async def loopy() -> None: print("KI!") -async def main() -> None: +async def main(): async with trio.open_nursery() as nursery: nursery.start_soon(loopy) nursery.start_soon(loopy) diff --git a/notes-to-self/lots-of-tasks.py b/notes-to-self/lots-of-tasks.py index d83617552..048c69a7e 100644 --- a/notes-to-self/lots-of-tasks.py +++ b/notes-to-self/lots-of-tasks.py @@ -6,7 +6,7 @@ COUNT = int(COUNT_STR) -async def main() -> None: +async def main(): async with trio.open_nursery() as nursery: for _ in range(COUNT): nursery.start_soon(trio.sleep, 1) diff --git a/notes-to-self/measure-listen-backlog.py b/notes-to-self/measure-listen-backlog.py index 7704ee7d4..b7253b86c 100644 --- a/notes-to-self/measure-listen-backlog.py +++ b/notes-to-self/measure-listen-backlog.py @@ -1,7 +1,7 @@ import trio -async def run_test(nominal_backlog) -> None: +async def run_test(nominal_backlog): print("--\nnominal:", nominal_backlog) listen_sock = trio.socket.socket() diff --git a/notes-to-self/ntp-example.py b/notes-to-self/ntp-example.py index 79b8cd0a5..2bb9f80fb 100644 --- a/notes-to-self/ntp-example.py +++ b/notes-to-self/ntp-example.py @@ -53,7 +53,7 @@ def extract_transmit_timestamp(ntp_packet): return base_time + offset -async def main() -> None: +async def main(): print("Our clock currently reads (in UTC):", datetime.datetime.utcnow()) # Look up some random NTP servers. diff --git a/notes-to-self/print-task-tree.py b/notes-to-self/print-task-tree.py index 5f9c535b0..54b97ec01 100644 --- a/notes-to-self/print-task-tree.py +++ b/notes-to-self/print-task-tree.py @@ -78,7 +78,7 @@ def task_tree_lines(task=None): return _render_subtree(task.name, rendered_children) -def print_task_tree(task=None) -> None: +def print_task_tree(task=None): for line in task_tree_lines(task): print(line) @@ -86,20 +86,20 @@ def print_task_tree(task=None) -> None: ################################################################ -async def child2() -> None: +async def child2(): async with trio.open_nursery() as nursery: nursery.start_soon(trio.sleep_forever) nursery.start_soon(trio.sleep_forever) -async def child1() -> None: +async def child1(): async with trio.open_nursery() as nursery: nursery.start_soon(child2) nursery.start_soon(child2) nursery.start_soon(trio.sleep_forever) -async def main() -> None: +async def main(): async with trio.open_nursery() as nursery0: nursery0.start_soon(child1) async with trio.open_nursery() as nursery1: diff --git a/notes-to-self/proxy-benchmarks.py b/notes-to-self/proxy-benchmarks.py index 85d7db1c0..830327cf4 100644 --- a/notes-to-self/proxy-benchmarks.py +++ b/notes-to-self/proxy-benchmarks.py @@ -8,7 +8,7 @@ class Proxy1: strategy = "__getattr__" works_for = "any attr" - def __init__(self, wrapped) -> None: + def __init__(self, wrapped): self._wrapped = wrapped def __getattr__(self, name): @@ -24,11 +24,11 @@ class Proxy2: strategy = "generated methods (getattr + closure)" works_for = "methods" - def __init__(self, wrapped) -> None: + def __init__(self, wrapped): self._wrapped = wrapped -def add_wrapper(cls, method) -> None: +def add_wrapper(cls, method): def wrapper(self, *args, **kwargs): return getattr(self._wrapped, method)(*args, **kwargs) @@ -45,11 +45,11 @@ class Proxy3: strategy = "generated methods (exec)" works_for = "methods" - def __init__(self, wrapped) -> None: + def __init__(self, wrapped): self._wrapped = wrapped -def add_wrapper(cls, method) -> None: +def add_wrapper(cls, method): code = textwrap.dedent( f""" def wrapper(self, *args, **kwargs): @@ -71,18 +71,18 @@ class Proxy4: strategy = "generated properties (getattr + closure)" works_for = "any attr" - def __init__(self, wrapped) -> None: + def __init__(self, wrapped): self._wrapped = wrapped -def add_wrapper(cls, attr) -> None: +def add_wrapper(cls, attr): def getter(self): return getattr(self._wrapped, attr) - def setter(self, newval) -> None: + def setter(self, newval): setattr(self._wrapped, attr, newval) - def deleter(self) -> None: + def deleter(self): delattr(self._wrapped, attr) setattr(cls, attr, property(getter, setter, deleter)) @@ -98,11 +98,11 @@ class Proxy5: strategy = "generated properties (exec)" works_for = "any attr" - def __init__(self, wrapped) -> None: + def __init__(self, wrapped): self._wrapped = wrapped -def add_wrapper(cls, attr) -> None: +def add_wrapper(cls, attr): code = textwrap.dedent( f""" def getter(self): @@ -131,7 +131,7 @@ class Proxy6: strategy = "copy attrs from wrappee to wrapper" works_for = "methods + constant attrs" - def __init__(self, wrapper) -> None: + def __init__(self, wrapper): self._wrapper = wrapper for method in methods: @@ -143,7 +143,7 @@ def __init__(self, wrapper) -> None: classes = [Proxy1, Proxy2, Proxy3, Proxy4, Proxy5, Proxy6] -def check(cls) -> None: +def check(cls): with open("/etc/passwd") as f: p = cls(f) assert p.fileno() == f.fileno() diff --git a/notes-to-self/reopen-pipe.py b/notes-to-self/reopen-pipe.py index 679c854ef..dbccd567d 100644 --- a/notes-to-self/reopen-pipe.py +++ b/notes-to-self/reopen-pipe.py @@ -4,7 +4,7 @@ import time -def check_reopen(r1, w) -> None: +def check_reopen(r1, w): try: print("Reopening read end") r2 = os.open(f"/proc/self/fd/{r1}", os.O_RDONLY) @@ -34,7 +34,7 @@ def check_reopen(r1, w) -> None: print("r2 definitely seems to be in non-blocking mode") # Check that r1 is really truly still in blocking mode - def sleep_then_write() -> None: + def sleep_then_write(): time.sleep(1) os.write(w, b"c") diff --git a/notes-to-self/schedule-timing.py b/notes-to-self/schedule-timing.py index 4fa88aeaf..11594b7cc 100644 --- a/notes-to-self/schedule-timing.py +++ b/notes-to-self/schedule-timing.py @@ -6,7 +6,7 @@ RUNNING = True -async def reschedule_loop(depth) -> None: +async def reschedule_loop(depth): if depth == 0: global LOOPS while RUNNING: @@ -17,7 +17,7 @@ async def reschedule_loop(depth) -> None: await reschedule_loop(depth - 1) -async def report_loop() -> None: +async def report_loop(): global RUNNING try: while True: @@ -33,7 +33,7 @@ async def report_loop() -> None: RUNNING = False -async def main() -> None: +async def main(): async with trio.open_nursery() as nursery: nursery.start_soon(reschedule_loop, 10) nursery.start_soon(report_loop) diff --git a/notes-to-self/socket-scaling.py b/notes-to-self/socket-scaling.py index 3d9199440..3bd074836 100644 --- a/notes-to-self/socket-scaling.py +++ b/notes-to-self/socket-scaling.py @@ -24,15 +24,15 @@ import trio.testing -async def main() -> None: +async def main(): for total in [10, 100, 500, 1_000, 10_000, 20_000, 30_000]: - def pt(desc, *, count=total, item="socket") -> None: + def pt(desc, *, count=total, item="socket"): nonlocal last_time now = time.perf_counter() total_ms = (now - last_time) * 1000 per_us = total_ms * 1000 / count - print(f"{desc}: {total_ms:.2f} ms total, {per_us:.2f} µs/{item}") + print(f"{desc}: {total_ms:.2f} ms total, {per_us:.2f} μs/{item}") last_time = now print(f"\n-- {total} sockets --") diff --git a/notes-to-self/ssl-close-notify/ssl-close-notify.py b/notes-to-self/ssl-close-notify/ssl-close-notify.py index 8df8cbb42..7a55b8c99 100644 --- a/notes-to-self/ssl-close-notify/ssl-close-notify.py +++ b/notes-to-self/ssl-close-notify/ssl-close-notify.py @@ -23,7 +23,7 @@ client_done = threading.Event() -def server_thread_fn() -> None: +def server_thread_fn(): server_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) server_ctx.load_cert_chain("trio-test-1.pem") server = server_ctx.wrap_socket( diff --git a/notes-to-self/ssl-handshake/ssl-handshake.py b/notes-to-self/ssl-handshake/ssl-handshake.py index 6b73339c8..1665ce333 100644 --- a/notes-to-self/ssl-handshake/ssl-handshake.py +++ b/notes-to-self/ssl-handshake/ssl-handshake.py @@ -9,7 +9,7 @@ server_ctx.load_cert_chain("trio-test-1.pem") -def _ssl_echo_serve_sync(sock) -> None: +def _ssl_echo_serve_sync(sock): try: wrapped = server_ctx.wrap_socket(sock, server_side=True) while True: @@ -37,7 +37,7 @@ def echo_server_connection(): class ManuallyWrappedSocket: - def __init__(self, ctx, sock, **kwargs) -> None: + def __init__(self, ctx, sock, **kwargs): self.incoming = ssl.MemoryBIO() self.outgoing = ssl.MemoryBIO() self.obj = ctx.wrap_bio(self.incoming, self.outgoing, **kwargs) @@ -71,13 +71,13 @@ def _retry(self, fn, *args): # then retry if necessary return ret - def do_handshake(self) -> None: + def do_handshake(self): self._retry(self.obj.do_handshake) def recv(self, bufsize): return self._retry(self.obj.read, bufsize) - def sendall(self, data) -> None: + def sendall(self, data): self._retry(self.obj.write, data) def unwrap(self): diff --git a/notes-to-self/thread-closure-bug-demo.py b/notes-to-self/thread-closure-bug-demo.py index 6985534bd..b5da68c33 100644 --- a/notes-to-self/thread-closure-bug-demo.py +++ b/notes-to-self/thread-closure-bug-demo.py @@ -23,7 +23,7 @@ def run_with_slow_tracefunc(fn): return fn() -def outer() -> None: +def outer(): x = 0 # We hide the done variable inside a list, because we want to use it to # communicate between the main thread and the looper thread, and the bug diff --git a/notes-to-self/thread-dispatch-bench.py b/notes-to-self/thread-dispatch-bench.py index 427cc0a62..e752c27e0 100644 --- a/notes-to-self/thread-dispatch-bench.py +++ b/notes-to-self/thread-dispatch-bench.py @@ -11,13 +11,13 @@ COUNT = 10000 -def worker(in_q, out_q) -> None: +def worker(in_q, out_q): while True: job = in_q.get() out_q.put(job()) -def main() -> None: +def main(): in_q = Queue() out_q = Queue() @@ -30,7 +30,7 @@ def main() -> None: in_q.put(lambda: None) out_q.get() end = time.monotonic() - print(f"{(end - start) / COUNT * 1e6:.2f} µs/job") + print(f"{(end - start) / COUNT * 1e6:.2f} μs/job") main() diff --git a/notes-to-self/time-wait.py b/notes-to-self/time-wait.py index a2a7dd165..edc1b3917 100644 --- a/notes-to-self/time-wait.py +++ b/notes-to-self/time-wait.py @@ -40,7 +40,7 @@ class Options: server = None listen2 = None - def set(self, which, sock) -> None: + def set(self, which, sock): value = getattr(self, which) if value is not None: sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, value) @@ -54,7 +54,7 @@ def describe(self): return "Set/unset: {}".format(", ".join(info)) -def time_wait(options) -> None: +def time_wait(options): print(options.describe()) # Find a pristine port (one we can definitely bind to without diff --git a/notes-to-self/trace.py b/notes-to-self/trace.py index 3294ce431..046412d3a 100644 --- a/notes-to-self/trace.py +++ b/notes-to-self/trace.py @@ -32,20 +32,20 @@ class Trace(trio.abc.Instrument): - def __init__(self, out) -> None: + def __init__(self, out): self.out = out self.out.write("[\n") self.ids = count() self._task_metadata(-1, "I/O manager") - def _write(self, **ev) -> None: + def _write(self, **ev): ev.setdefault("pid", os.getpid()) if ev["ph"] != "M": ev.setdefault("ts", trio.current_time() * 1e6) self.out.write(json.dumps(ev)) self.out.write(",\n") - def _task_metadata(self, tid, name) -> None: + def _task_metadata(self, tid, name): self._write( name="thread_name", ph="M", @@ -59,7 +59,7 @@ def _task_metadata(self, tid, name) -> None: args={"sort_index": tid}, ) - def task_spawned(self, task) -> None: + def task_spawned(self, task): self._task_metadata(task._counter, task.name) self._write( name="task lifetime", @@ -67,28 +67,28 @@ def task_spawned(self, task) -> None: tid=task._counter, ) - def task_exited(self, task) -> None: + def task_exited(self, task): self._write( name="task lifetime", ph="E", tid=task._counter, ) - def before_task_step(self, task) -> None: + def before_task_step(self, task): self._write( name="running", ph="B", tid=task._counter, ) - def after_task_step(self, task) -> None: + def after_task_step(self, task): self._write( name="running", ph="E", tid=task._counter, ) - def task_scheduled(self, task) -> None: + def task_scheduled(self, task): try: waker = trio.lowlevel.current_task() except RuntimeError: @@ -108,14 +108,14 @@ def task_scheduled(self, task) -> None: tid=task._counter, ) - def before_io_wait(self, timeout) -> None: + def before_io_wait(self, timeout): self._write( name="I/O wait", ph="B", tid=-1, ) - def after_io_wait(self, timeout) -> None: + def after_io_wait(self, timeout): self._write( name="I/O wait", ph="E", @@ -123,19 +123,19 @@ def after_io_wait(self, timeout) -> None: ) -async def child1() -> None: +async def child1(): print(" child1: started! sleeping now...") await trio.sleep(1) print(" child1: exiting!") -async def child2() -> None: +async def child2(): print(" child2: started! sleeping now...") await trio.sleep(1) print(" child2: exiting!") -async def parent() -> None: +async def parent(): print("parent: started!") async with trio.open_nursery() as nursery: print("parent: spawning child1...") diff --git a/notes-to-self/trivial-err.py b/notes-to-self/trivial-err.py index 1b0b7adde..6c32617c7 100644 --- a/notes-to-self/trivial-err.py +++ b/notes-to-self/trivial-err.py @@ -1,30 +1,29 @@ import sys -from typing import NoReturn import trio sys.stderr = sys.stdout -async def child1() -> NoReturn: +async def child1(): raise ValueError -async def child2() -> None: +async def child2(): async with trio.open_nursery() as nursery: nursery.start_soon(grandchild1) nursery.start_soon(grandchild2) -async def grandchild1() -> NoReturn: +async def grandchild1(): raise KeyError -async def grandchild2() -> NoReturn: +async def grandchild2(): raise NameError("Bob") -async def main() -> None: +async def main(): async with trio.open_nursery() as nursery: nursery.start_soon(child1) nursery.start_soon(child2) diff --git a/notes-to-self/trivial.py b/notes-to-self/trivial.py index f02d5a297..405d92daf 100644 --- a/notes-to-self/trivial.py +++ b/notes-to-self/trivial.py @@ -1,7 +1,7 @@ import trio -async def foo() -> int: +async def foo(): print("in foo!") return 3 diff --git a/notes-to-self/wakeup-fd-racer.py b/notes-to-self/wakeup-fd-racer.py index a48384942..97faa0dfd 100644 --- a/notes-to-self/wakeup-fd-racer.py +++ b/notes-to-self/wakeup-fd-racer.py @@ -16,13 +16,13 @@ signal_raise = getattr(_lib, "raise") else: - def signal_raise(signum) -> None: + def signal_raise(signum): # Use pthread_kill to make sure we're actually using the wakeup fd on # Unix signal.pthread_kill(threading.get_ident(), signum) -def raise_SIGINT_soon() -> None: +def raise_SIGINT_soon(): time.sleep(1) signal_raise(signal.SIGINT) # Sending 2 signals becomes reliable, as we'd expect (because we need @@ -41,7 +41,7 @@ def drain(sock): return total -def main() -> None: +def main(): writer, reader = socket.socketpair() writer.setblocking(False) reader.setblocking(False) diff --git a/notes-to-self/win-waitable-timer.py b/notes-to-self/win-waitable-timer.py index 848f8229e..b8d9af6ca 100644 --- a/notes-to-self/win-waitable-timer.py +++ b/notes-to-self/win-waitable-timer.py @@ -96,7 +96,7 @@ PROCESS_LEAP_SECOND_INFO_FLAG_ENABLE_SIXTY_SECOND = 1 -def set_leap_seconds_enabled(enabled) -> None: +def set_leap_seconds_enabled(enabled): plsi = ffi.new("PROCESS_LEAP_SECOND_INFO*") if enabled: plsi.Flags = PROCESS_LEAP_SECOND_INFO_FLAG_ENABLE_SIXTY_SECOND @@ -160,7 +160,7 @@ def py_datetime_to_win_filetime(dt): return round((dt - FILETIME_EPOCH).total_seconds() * FILETIME_TICKS_PER_SECOND) -async def main() -> None: +async def main(): h = kernel32.CreateWaitableTimerW(ffi.NULL, True, ffi.NULL) if not h: raise_winerror() From 8123b72b3259eba128c7231f7c5db8995221d885 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 21 Oct 2024 10:56:18 -0500 Subject: [PATCH 12/52] Disable `ANN401` --- pyproject.toml | 1 + src/trio/_core/_concat_tb.py | 2 +- src/trio/_core/_instrumentation.py | 2 +- src/trio/_core/_run.py | 4 ++-- src/trio/_core/_tests/test_guest_mode.py | 4 ++-- src/trio/_core/_traps.py | 8 ++++---- src/trio/_ssl.py | 2 +- src/trio/_tests/test_subprocess.py | 8 ++++---- 8 files changed, 16 insertions(+), 15 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2db6ab213..a0b66ed42 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -142,6 +142,7 @@ extend-ignore = [ 'PERF203', # try-except-in-loop (not always possible to refactor) 'PT012', # multiple statements in pytest.raises block 'SIM117', # multiple-with-statements (messes up lots of context-based stuff and looks bad) + 'ANN401', # any-type (mypy's `disallow_any_explicit` is better) ] [tool.ruff.lint.per-file-ignores] diff --git a/src/trio/_core/_concat_tb.py b/src/trio/_core/_concat_tb.py index 919c303e3..5d84118cd 100644 --- a/src/trio/_core/_concat_tb.py +++ b/src/trio/_core/_concat_tb.py @@ -88,7 +88,7 @@ def copy_tb(base_tb: TracebackType, tb_next: TracebackType | None) -> TracebackT # cpython/pypy in current type checkers. def controller( # type: ignore[no-any-unimported] operation: tputil.ProxyOperation, - ) -> Any | None: # noqa: ANN401 # Using Any + ) -> Any | None: # Rationale for pragma: I looked fairly carefully and tried a few # things, and AFAICT it's not actually possible to get any # 'opname' that isn't __getattr__ or __getattribute__. So there's diff --git a/src/trio/_core/_instrumentation.py b/src/trio/_core/_instrumentation.py index 0139b4dea..d5d6e2c83 100644 --- a/src/trio/_core/_instrumentation.py +++ b/src/trio/_core/_instrumentation.py @@ -89,7 +89,7 @@ def remove_instrument(self, instrument: Instrument) -> None: def call( self, hookname: str, - *args: Any, # noqa: ANN401 # Using Any + *args: Any, ) -> None: """Call hookname(*args) on each applicable instrument. diff --git a/src/trio/_core/_run.py b/src/trio/_core/_run.py index d66fe2e12..882fd17dc 100644 --- a/src/trio/_core/_run.py +++ b/src/trio/_core/_run.py @@ -1283,7 +1283,7 @@ async def start( async_fn: Callable[..., Awaitable[object]], *args: object, name: object = None, - ) -> Any: # noqa: ANN401 # Using Any + ) -> Any: r"""Creates and initializes a child task. Like :meth:`start_soon`, but blocks until the new task has @@ -2826,7 +2826,7 @@ class _TaskStatusIgnored(TaskStatus[Any]): def __repr__(self) -> str: return "TASK_STATUS_IGNORED" - def started(self, value: Any = None) -> None: # noqa: ANN401 # Using Any + def started(self, value: Any = None) -> None: pass diff --git a/src/trio/_core/_tests/test_guest_mode.py b/src/trio/_core/_tests/test_guest_mode.py index a6edbb13f..303c3a229 100644 --- a/src/trio/_core/_tests/test_guest_mode.py +++ b/src/trio/_core/_tests/test_guest_mode.py @@ -52,7 +52,7 @@ def trivial_guest_run( trio_fn: Callable[..., Awaitable[T]], *, in_host_after_start: Callable[[], None] | None = None, - **start_guest_run_kwargs: Any, # noqa: ANN401 # Using Any, too diverse + **start_guest_run_kwargs: Any, ) -> T: todo: queue.Queue[tuple[str, Outcome[T] | Callable[..., object]]] = queue.Queue() @@ -436,7 +436,7 @@ def aiotrio_run( trio_fn: Callable[..., Awaitable[T]], *, pass_not_threadsafe: bool = True, - **start_guest_run_kwargs: Any, # noqa: ANN401 # Using Any, too diverse + **start_guest_run_kwargs: Any, ) -> T: loop = asyncio.new_event_loop() diff --git a/src/trio/_core/_traps.py b/src/trio/_core/_traps.py index 9222c2f10..fc31a182a 100644 --- a/src/trio/_core/_traps.py +++ b/src/trio/_core/_traps.py @@ -25,7 +25,7 @@ # tracking machinery. Since our traps are public APIs, we make them real async # functions, and then this helper takes care of the actual yield: @types.coroutine -def _async_yield(obj: Any) -> Any: # type: ignore[misc] # noqa: ANN401 +def _async_yield(obj: Any) -> Any: # type: ignore[misc] return (yield obj) @@ -79,7 +79,7 @@ class WaitTaskRescheduled: # with a bad value. async def wait_task_rescheduled( abort_func: Callable[[RaiseCancelT], Abort], -) -> Any: # noqa: ANN401 # Any used +) -> Any: """Put the current task to sleep, with cancellation support. This is the lowest-level API for blocking in Trio. Every time a @@ -189,7 +189,7 @@ class PermanentlyDetachCoroutineObject: async def permanently_detach_coroutine_object( final_outcome: outcome.Outcome[Any], -) -> Any: # noqa: ANN401 # Any used +) -> Any: """Permanently detach the current task from the Trio scheduler. Normally, a Trio task doesn't exit until its coroutine object exits. When @@ -222,7 +222,7 @@ async def permanently_detach_coroutine_object( async def temporarily_detach_coroutine_object( abort_func: Callable[[RaiseCancelT], Abort], -) -> Any: # noqa: ANN401 # Any used +) -> Any: """Temporarily detach the current coroutine object from the Trio scheduler. diff --git a/src/trio/_ssl.py b/src/trio/_ssl.py index e5a0cdabd..df1cbc37b 100644 --- a/src/trio/_ssl.py +++ b/src/trio/_ssl.py @@ -413,7 +413,7 @@ def __init__( "version", } - def __getattr__(self, name: str) -> Any: # noqa: ANN401 # Any used + def __getattr__(self, name: str) -> Any: if name in self._forwarded: if name in self._after_handshake and not self._handshook.done: raise NeedHandshakeError(f"call do_handshake() before calling {name!r}") diff --git a/src/trio/_tests/test_subprocess.py b/src/trio/_tests/test_subprocess.py index 2908e2294..3be99b6d3 100644 --- a/src/trio/_tests/test_subprocess.py +++ b/src/trio/_tests/test_subprocess.py @@ -92,8 +92,8 @@ def got_signal(proc: Process, sig: SignalType) -> bool: @asynccontextmanager # type: ignore[misc] # Any in decorated async def open_process_then_kill( - *args: Any, # noqa: ANN401 # Any used, different OS -> different args - **kwargs: Any, # noqa: ANN401 + *args: Any, + **kwargs: Any, ) -> AsyncIterator[Process]: proc = await open_process(*args, **kwargs) try: @@ -105,8 +105,8 @@ async def open_process_then_kill( @asynccontextmanager # type: ignore[misc] # Any in decorated async def run_process_in_nursery( - *args: Any, # noqa: ANN401 # Any used, different OS -> different args - **kwargs: Any, # noqa: ANN401 + *args: Any, + **kwargs: Any, ) -> AsyncIterator[Process]: async with _core.open_nursery() as nursery: kwargs.setdefault("check", False) From 42be7f365dba82634f3ff72d2a30fe528e40c52b Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:01:31 -0500 Subject: [PATCH 13/52] Stop using `kwargs` altogether and simply define the parameters Co-authored-by: John Litborn <11260241+jakkdl@users.noreply.github.com> --- pyproject.toml | 2 +- .../_tests/test_highlevel_open_tcp_stream.py | 6 +- src/trio/_tests/test_socket.py | 55 +++++++++++++++---- src/trio/_tests/test_ssl.py | 42 ++++++++++---- 4 files changed, 80 insertions(+), 25 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a0b66ed42..ab2c0dd82 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -135,6 +135,7 @@ extend-ignore = [ 'A002', # builtin-argument-shadowing 'ANN101', # missing-type-self 'ANN102', # missing-type-cls + 'ANN401', # any-type (mypy's `disallow_any_explicit` is better) 'E402', # module-import-not-at-top-of-file (usually OS-specific) 'E501', # line-too-long 'F403', # undefined-local-with-import-star @@ -142,7 +143,6 @@ extend-ignore = [ 'PERF203', # try-except-in-loop (not always possible to refactor) 'PT012', # multiple statements in pytest.raises block 'SIM117', # multiple-with-statements (messes up lots of context-based stuff and looks bad) - 'ANN401', # any-type (mypy's `disallow_any_explicit` is better) ] [tool.ruff.lint.per-file-ignores] diff --git a/src/trio/_tests/test_highlevel_open_tcp_stream.py b/src/trio/_tests/test_highlevel_open_tcp_stream.py index f05166a28..ebe30ef78 100644 --- a/src/trio/_tests/test_highlevel_open_tcp_stream.py +++ b/src/trio/_tests/test_highlevel_open_tcp_stream.py @@ -360,7 +360,8 @@ async def run_scenario( # If this is True, we require there to be an exception, and return # (exception, scenario object) expect_error: tuple[type[BaseException], ...] | type[BaseException] = (), - **kwargs: str | float | None, + happy_eyeballs_delay: float | None = 0.25, + local_address: str | None = None, ) -> tuple[SocketType, Scenario] | tuple[BaseException, Scenario]: supported_families = set() if ipv4_supported: @@ -378,7 +379,8 @@ async def run_scenario( stream = await open_tcp_stream( "test.example.com", port, - **kwargs, # type: ignore[arg-type] + happy_eyeballs_delay=happy_eyeballs_delay, + local_address=local_address, ) assert expect_error == () scenario.check(stream.socket) diff --git a/src/trio/_tests/test_socket.py b/src/trio/_tests/test_socket.py index a403272b4..43c9df239 100644 --- a/src/trio/_tests/test_socket.py +++ b/src/trio/_tests/test_socket.py @@ -51,11 +51,15 @@ def __init__(self, orig_getaddrinfo: Callable[..., GetAddrInfoResponse]) -> None # get a normalized getaddrinfo argument tuple def _frozenbind( self, - *args: bytes | str | int | None, - **kwargs: bytes | str | int | None, + host: bytes | str | None, + port: bytes | str | int | None, + family: int = 0, + type: int = 0, + proto: int = 0, + flags: int = 0, ) -> tuple[Any, ...]: sig = inspect.signature(self._orig_getaddrinfo) - bound = sig.bind(*args, **kwargs) + bound = sig.bind(host, port, family=family, type=type, proto=proto, flags=flags) bound.apply_defaults() frozenbound = bound.args assert not bound.kwargs @@ -64,22 +68,53 @@ def _frozenbind( def set( self, response: GetAddrInfoResponse | str, - *args: bytes | str | int | None, - **kwargs: bytes | str | int | None, + host: bytes | str | None, + port: bytes | str | int | None, + family: int = 0, + type: int = 0, + proto: int = 0, + flags: int = 0, ) -> None: - self._responses[self._frozenbind(*args, **kwargs)] = response + self._responses[ + self._frozenbind( + host, + port, + family=family, + type=type, + proto=proto, + flags=flags, + ) + ] = response def getaddrinfo( self, - *args: bytes | str | int | None, - **kwargs: bytes | str | int | None, + host: bytes | str | None, + port: bytes | str | int | None, + family: int = 0, + type: int = 0, + proto: int = 0, + flags: int = 0, ) -> GetAddrInfoResponse | str: - bound = self._frozenbind(*args, **kwargs) + bound = self._frozenbind( + host, + port, + family=family, + type=type, + proto=proto, + flags=flags, + ) self.record.append(bound) if bound in self._responses: return self._responses[bound] elif bound[-1] & stdlib_socket.AI_NUMERICHOST: - return self._orig_getaddrinfo(*args, **kwargs) + return self._orig_getaddrinfo( + host, + port, + family=family, + type=type, + proto=proto, + flags=flags, + ) else: raise RuntimeError(f"gai called with unexpected arguments {bound}") diff --git a/src/trio/_tests/test_ssl.py b/src/trio/_tests/test_ssl.py index 3777e8392..e732efabb 100644 --- a/src/trio/_tests/test_ssl.py +++ b/src/trio/_tests/test_ssl.py @@ -174,7 +174,7 @@ def ssl_echo_serve_sync( # (running in a thread). Useful for testing making connections with different # SSLContexts. @asynccontextmanager -async def ssl_echo_server_raw(**kwargs: bool) -> AsyncIterator[SocketStream]: +async def ssl_echo_server_raw(expect_fail: bool = False) -> AsyncIterator[SocketStream]: a, b = stdlib_socket.socketpair() async with trio.open_nursery() as nursery: # Exiting the 'with a, b' context manager closes the sockets, which @@ -183,7 +183,7 @@ async def ssl_echo_server_raw(**kwargs: bool) -> AsyncIterator[SocketStream]: with a, b: nursery.start_soon( trio.to_thread.run_sync, - partial(ssl_echo_serve_sync, b, **kwargs), + partial(ssl_echo_serve_sync, b, expect_fail=expect_fail), ) yield SocketStream(tsocket.from_stdlib_socket(a)) @@ -194,9 +194,9 @@ async def ssl_echo_server_raw(**kwargs: bool) -> AsyncIterator[SocketStream]: @asynccontextmanager async def ssl_echo_server( client_ctx: SSLContext, - **kwargs: bool, + expect_fail: bool = False, ) -> AsyncIterator[SSLStream[Stream]]: - async with ssl_echo_server_raw(**kwargs) as sock: + async with ssl_echo_server_raw(expect_fail=expect_fail) as sock: yield SSLStream(sock, client_ctx, server_hostname="trio-test-1.example.org") @@ -396,9 +396,9 @@ async def do_test( @contextmanager def virtual_ssl_echo_server( client_ctx: SSLContext, - **kwargs: Callable[[str], Awaitable[None]] | None, + sleeper: Callable[[str], Awaitable[None]] | None = None, ) -> Iterator[SSLStream[PyOpenSSLEchoStream]]: - fakesock = PyOpenSSLEchoStream(**kwargs) + fakesock = PyOpenSSLEchoStream(sleeper=sleeper) yield SSLStream(fakesock, client_ctx, server_hostname="trio-test-1.example.org") @@ -434,13 +434,20 @@ def ssl_wrap_pair( def ssl_memory_stream_pair( client_ctx: SSLContext, - **kwargs: dict[str, str | bytes | bool | None] | None, + client_kwargs: dict[str, str | bytes | bool | None] | None = None, + server_kwargs: dict[str, str | bytes | bool | None] | None = None, ) -> tuple[ SSLStream[MemoryStapledStream], SSLStream[MemoryStapledStream], ]: client_transport, server_transport = memory_stream_pair() - return ssl_wrap_pair(client_ctx, client_transport, server_transport, **kwargs) + return ssl_wrap_pair( + client_ctx, + client_transport, + server_transport, + client_kwargs=client_kwargs, + server_kwargs=server_kwargs, + ) MyStapledStream: TypeAlias = StapledStream[SendStream, ReceiveStream] @@ -448,13 +455,20 @@ def ssl_memory_stream_pair( def ssl_lockstep_stream_pair( client_ctx: SSLContext, - **kwargs: dict[str, str | bytes | bool | None] | None, + client_kwargs: dict[str, str | bytes | bool | None] | None = None, + server_kwargs: dict[str, str | bytes | bool | None] | None = None, ) -> tuple[ SSLStream[MyStapledStream], SSLStream[MyStapledStream], ]: client_transport, server_transport = lockstep_stream_pair() - return ssl_wrap_pair(client_ctx, client_transport, server_transport, **kwargs) + return ssl_wrap_pair( + client_ctx, + client_transport, + server_transport, + client_kwargs=client_kwargs, + server_kwargs=server_kwargs, + ) # Simple smoke test for handshake/send/receive/shutdown talking to a @@ -1332,13 +1346,17 @@ async def test_getpeercert(client_ctx: SSLContext) -> None: async def test_SSLListener(client_ctx: SSLContext) -> None: async def setup( - **kwargs: bool, + https_compatible: bool = False, ) -> tuple[tsocket.SocketType, SSLListener[SocketStream], SSLStream[SocketStream]]: listen_sock = tsocket.socket() await listen_sock.bind(("127.0.0.1", 0)) listen_sock.listen(1) socket_listener = SocketListener(listen_sock) - ssl_listener = SSLListener(socket_listener, SERVER_CTX, **kwargs) + ssl_listener = SSLListener( + socket_listener, + SERVER_CTX, + https_compatible=https_compatible, + ) transport_client = await open_tcp_stream(*listen_sock.getsockname()) ssl_client = SSLStream( From 6e91b753a2ebb846bb5c600fa312354b8a694a7a Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Sun, 27 Oct 2024 01:12:12 -0500 Subject: [PATCH 14/52] Enable mypy's `disallow_any_explicit` flag. agreed. disable ANN401 for now and enable `disallow_any_explicit` in a separate PR. Possibly same for `disallow_untyped_defs`. _Originally posted by @jakkdl in https://github.com/python-trio/trio/pull/3098#discussion_r1807799021_ --- pyproject.toml | 1 + src/trio/_core/_concat_tb.py | 5 +- src/trio/_core/_entry_queue.py | 3 +- src/trio/_core/_generated_run.py | 4 +- src/trio/_core/_instrumentation.py | 12 ++- src/trio/_core/_io_windows.py | 8 +- src/trio/_core/_ki.py | 6 +- src/trio/_core/_run.py | 77 +++++++++++-------- src/trio/_core/_tests/test_guest_mode.py | 11 ++- src/trio/_core/_tests/test_run.py | 48 +++++++++--- src/trio/_core/_thread_cache.py | 2 +- src/trio/_core/_traps.py | 14 ++-- src/trio/_dtls.py | 16 ++-- src/trio/_file_io.py | 3 +- src/trio/_highlevel_open_tcp_stream.py | 17 ++-- src/trio/_highlevel_serve_listeners.py | 6 +- src/trio/_path.py | 3 +- src/trio/_socket.py | 20 +++-- src/trio/_ssl.py | 16 +++- ...deprecate_strict_exception_groups_false.py | 2 +- .../test_highlevel_open_tcp_listeners.py | 9 ++- .../_tests/test_highlevel_open_tcp_stream.py | 12 ++- src/trio/_tests/test_highlevel_ssl_helpers.py | 6 +- src/trio/_tests/test_socket.py | 43 ++++++++--- src/trio/_tests/test_ssl.py | 18 ++++- src/trio/_tests/test_subprocess.py | 6 +- src/trio/_tests/test_testing_raisesgroup.py | 6 +- src/trio/_tests/test_threads.py | 3 +- src/trio/_tests/test_util.py | 14 +++- src/trio/_threads.py | 18 +++-- src/trio/_tools/mypy_annotate.py | 2 +- src/trio/_util.py | 23 ++++-- src/trio/testing/_fake_net.py | 27 +++++-- test-requirements.in | 2 +- test-requirements.txt | 4 +- 35 files changed, 323 insertions(+), 144 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index adf2ccbe9..0d84442d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -183,6 +183,7 @@ warn_return_any = true # Avoid subtle backsliding disallow_any_decorated = true +disallow_any_explicit = true disallow_any_generics = true disallow_any_unimported = true disallow_incomplete_defs = true diff --git a/src/trio/_core/_concat_tb.py b/src/trio/_core/_concat_tb.py index 2ddaf2e8e..ed785cb64 100644 --- a/src/trio/_core/_concat_tb.py +++ b/src/trio/_core/_concat_tb.py @@ -86,7 +86,10 @@ def copy_tb(base_tb: TracebackType, tb_next: TracebackType | None) -> TracebackT def copy_tb(base_tb: TracebackType, tb_next: TracebackType | None) -> TracebackType: # tputil.ProxyOperation is PyPy-only, and there's no way to specify # cpython/pypy in current type checkers. - def controller(operation: tputil.ProxyOperation) -> Any | None: # type: ignore[no-any-unimported] + # Explicit "Any" is not allowed + def controller( # type: ignore[no-any-unimported,misc] + operation: tputil.ProxyOperation, + ) -> Any | None: # Rationale for pragma: I looked fairly carefully and tried a few # things, and AFAICT it's not actually possible to get any # 'opname' that isn't __getattr__ or __getattribute__. So there's diff --git a/src/trio/_core/_entry_queue.py b/src/trio/_core/_entry_queue.py index 332441a3a..0691de351 100644 --- a/src/trio/_core/_entry_queue.py +++ b/src/trio/_core/_entry_queue.py @@ -16,7 +16,8 @@ PosArgsT = TypeVarTuple("PosArgsT") -Function = Callable[..., object] +# Explicit "Any" is not allowed +Function = Callable[..., object] # type: ignore[misc] Job = tuple[Function, tuple[object, ...]] diff --git a/src/trio/_core/_generated_run.py b/src/trio/_core/_generated_run.py index b5957a134..0b68b80fd 100644 --- a/src/trio/_core/_generated_run.py +++ b/src/trio/_core/_generated_run.py @@ -4,7 +4,7 @@ from __future__ import annotations import sys -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from ._ki import LOCALS_KEY_KI_PROTECTION_ENABLED from ._run import _NO_SEND, GLOBAL_RUN_CONTEXT, RunStatistics, Task @@ -102,7 +102,7 @@ def current_root_task() -> Task | None: raise RuntimeError("must be called from async context") from None -def reschedule(task: Task, next_send: Outcome[Any] = _NO_SEND) -> None: +def reschedule(task: Task, next_send: Outcome[object] = _NO_SEND) -> None: """Reschedule the given task with the given :class:`outcome.Outcome`. diff --git a/src/trio/_core/_instrumentation.py b/src/trio/_core/_instrumentation.py index 905e81c37..ea807fe4d 100644 --- a/src/trio/_core/_instrumentation.py +++ b/src/trio/_core/_instrumentation.py @@ -11,12 +11,14 @@ INSTRUMENT_LOGGER = logging.getLogger("trio.abc.Instrument") -F = TypeVar("F", bound=Callable[..., Any]) +# Explicit "Any" is not allowed +F = TypeVar("F", bound=Callable[..., Any]) # type: ignore[misc] # Decorator to mark methods public. This does nothing by itself, but # trio/_tools/gen_exports.py looks for it. -def _public(fn: F) -> F: +# Explicit "Any" is not allowed +def _public(fn: F) -> F: # type: ignore[misc] return fn @@ -89,7 +91,11 @@ def remove_instrument(self, instrument: Instrument) -> None: if not instruments: del self[hookname] - def call(self, hookname: str, *args: Any) -> None: + def call( + self, + hookname: str, + *args: object, + ) -> None: """Call hookname(*args) on each applicable instrument. You must first check whether there are any instruments installed for diff --git a/src/trio/_core/_io_windows.py b/src/trio/_core/_io_windows.py index 80b62d477..7effe76b0 100644 --- a/src/trio/_core/_io_windows.py +++ b/src/trio/_core/_io_windows.py @@ -253,9 +253,10 @@ class AFDWaiters: # object, because we need to keep all these objects alive until the operation # finishes, even if we're throwing it away. @attrs.frozen(eq=False) -class AFDPollOp: +# Explicit "Any" is not allowed +class AFDPollOp: # type: ignore[misc] lpOverlapped: CData - poll_info: Any + poll_info: Any # type: ignore[misc] waiters: AFDWaiters afd_group: AFDGroup @@ -684,7 +685,8 @@ def _refresh_afd(self, base_handle: Handle) -> None: lpOverlapped = ffi.new("LPOVERLAPPED") - poll_info: Any = ffi.new("AFD_POLL_INFO *") + # Explicit "Any" is not allowed + poll_info: Any = ffi.new("AFD_POLL_INFO *") # type: ignore[misc] poll_info.Timeout = 2**63 - 1 # INT64_MAX poll_info.NumberOfHandles = 1 poll_info.Exclusive = 0 diff --git a/src/trio/_core/_ki.py b/src/trio/_core/_ki.py index a8431f89d..46729685f 100644 --- a/src/trio/_core/_ki.py +++ b/src/trio/_core/_ki.py @@ -10,7 +10,8 @@ from .._util import is_main_thread -CallableT = TypeVar("CallableT", bound="Callable[..., object]") +# Explicit "Any" is not allowed +CallableT = TypeVar("CallableT", bound="Callable[..., object]") # type: ignore[misc] RetT = TypeVar("RetT") if TYPE_CHECKING: @@ -191,7 +192,8 @@ def wrapper(*args: ArgsT.args, **kwargs: ArgsT.kwargs) -> RetT: class KIProtectionSignature(Protocol): __name__: str - def __call__(self, f: CallableT, /) -> CallableT: + # Explicit "Any" is not allowed + def __call__(self, f: CallableT, /) -> CallableT: # type: ignore[misc] pass diff --git a/src/trio/_core/_run.py b/src/trio/_core/_run.py index cba7a8dec..4cdcfbf77 100644 --- a/src/trio/_core/_run.py +++ b/src/trio/_core/_run.py @@ -82,14 +82,16 @@ StatusT = TypeVar("StatusT") StatusT_contra = TypeVar("StatusT_contra", contravariant=True) -FnT = TypeVar("FnT", bound="Callable[..., Any]") +# Explicit "Any" is not allowed +FnT = TypeVar("FnT", bound="Callable[..., Any]") # type: ignore[misc] RetT = TypeVar("RetT") DEADLINE_HEAP_MIN_PRUNE_THRESHOLD: Final = 1000 # Passed as a sentinel -_NO_SEND: Final[Outcome[Any]] = cast("Outcome[Any]", object()) +# Explicit "Any" is not allowed +_NO_SEND: Final[Outcome[Any]] = cast("Outcome[Any]", object()) # type: ignore[misc] # Used to track if an exceptiongroup can be collapsed NONSTRICT_EXCEPTIONGROUP_NOTE = 'This is a "loose" ExceptionGroup, and may be collapsed by Trio if it only contains one exception - typically after `Cancelled` has been stripped from it. Note this has consequences for exception handling, and strict_exception_groups=True is recommended.' @@ -102,7 +104,8 @@ class _NoStatus(metaclass=NoPublicConstructor): # Decorator to mark methods public. This does nothing by itself, but # trio/_tools/gen_exports.py looks for it. -def _public(fn: FnT) -> FnT: +# Explicit "Any" is not allowed +def _public(fn: FnT) -> FnT: # type: ignore[misc] return fn @@ -1172,7 +1175,12 @@ def _check_nursery_closed(self) -> None: self._parent_waiting_in_aexit = False GLOBAL_RUN_CONTEXT.runner.reschedule(self._parent_task) - def _child_finished(self, task: Task, outcome: Outcome[Any]) -> None: + # Explicit "Any" is not allowed + def _child_finished( # type: ignore[misc] + self, + task: Task, + outcome: Outcome[Any], + ) -> None: self._children.remove(task) if isinstance(outcome, Error): self._add_exc(outcome.error) @@ -1278,7 +1286,8 @@ def start_soon( """ GLOBAL_RUN_CONTEXT.runner.spawn_impl(async_fn, args, self, name) - async def start( + # Explicit "Any" is not allowed + async def start( # type: ignore[misc] self, async_fn: Callable[..., Awaitable[object]], *args: object, @@ -1334,7 +1343,8 @@ async def async_fn(arg1, arg2, *, task_status=trio.TASK_STATUS_IGNORED): # set strict_exception_groups = True to make sure we always unwrap # *this* nursery's exceptiongroup async with open_nursery(strict_exception_groups=True) as old_nursery: - task_status: _TaskStatus[Any] = _TaskStatus(old_nursery, self) + # Explicit "Any" is not allowed + task_status: _TaskStatus[Any] = _TaskStatus(old_nursery, self) # type: ignore[misc] thunk = functools.partial(async_fn, task_status=task_status) task = GLOBAL_RUN_CONTEXT.runner.spawn_impl( thunk, @@ -1375,9 +1385,10 @@ def __del__(self) -> None: @final @attrs.define(eq=False, repr=False) -class Task(metaclass=NoPublicConstructor): +class Task(metaclass=NoPublicConstructor): # type: ignore[misc] _parent_nursery: Nursery | None - coro: Coroutine[Any, Outcome[object], Any] + # Explicit "Any" is not allowed + coro: Coroutine[Any, Outcome[object], Any] # type: ignore[misc] _runner: Runner name: str context: contextvars.Context @@ -1394,10 +1405,11 @@ class Task(metaclass=NoPublicConstructor): # tracebacks with extraneous frames. # - for scheduled tasks, custom_sleep_data is None # Tasks start out unscheduled. - _next_send_fn: Callable[[Any], object] | None = None - _next_send: Outcome[Any] | None | BaseException = None + # Explicit "Any" is not allowed + _next_send_fn: Callable[[Any], object] | None = None # type: ignore[misc] + _next_send: Outcome[Any] | None | BaseException = None # type: ignore[misc] _abort_func: Callable[[_core.RaiseCancelT], Abort] | None = None - custom_sleep_data: Any = None + custom_sleep_data: Any = None # type: ignore[misc] # For introspection and nursery.start() _child_nurseries: list[Nursery] = attrs.Factory(list) @@ -1465,7 +1477,8 @@ def print_stack_for_task(task): """ # Ignore static typing as we're doing lots of dynamic introspection - coro: Any = self.coro + # Explicit "Any" is not allowed + coro: Any = self.coro # type: ignore[misc] while coro is not None: if hasattr(coro, "cr_frame"): # A real coroutine @@ -1618,13 +1631,16 @@ class RunStatistics: @attrs.define(eq=False) -class GuestState: +# Explicit "Any" is not allowed +class GuestState: # type: ignore[misc] runner: Runner run_sync_soon_threadsafe: Callable[[Callable[[], object]], object] run_sync_soon_not_threadsafe: Callable[[Callable[[], object]], object] - done_callback: Callable[[Outcome[Any]], object] + # Explicit "Any" is not allowed + done_callback: Callable[[Outcome[Any]], object] # type: ignore[misc] unrolled_run_gen: Generator[float, EventResult, None] - unrolled_run_next_send: Outcome[Any] = attrs.Factory(lambda: Value(None)) + # Explicit "Any" is not allowed + unrolled_run_next_send: Outcome[Any] = attrs.Factory(lambda: Value(None)) # type: ignore[misc] def guest_tick(self) -> None: prev_library, sniffio_library.name = sniffio_library.name, "trio" @@ -1669,7 +1685,8 @@ def in_main_thread() -> None: @attrs.define(eq=False) -class Runner: +# Explicit "Any" is not allowed +class Runner: # type: ignore[misc] clock: Clock instruments: Instruments io_manager: TheIOManager @@ -1677,7 +1694,8 @@ class Runner: strict_exception_groups: bool # Run-local values, see _local.py - _locals: dict[_core.RunVar[Any], Any] = attrs.Factory(dict) + # Explicit "Any" is not allowed + _locals: dict[_core.RunVar[Any], object] = attrs.Factory(dict) # type: ignore[misc] runq: deque[Task] = attrs.Factory(deque) tasks: set[Task] = attrs.Factory(set) @@ -1688,7 +1706,7 @@ class Runner: system_nursery: Nursery | None = None system_context: contextvars.Context = attrs.field(kw_only=True) main_task: Task | None = None - main_task_outcome: Outcome[Any] | None = None + main_task_outcome: Outcome[object] | None = None entry_queue: EntryQueue = attrs.Factory(EntryQueue) trio_token: TrioToken | None = None @@ -1780,12 +1798,8 @@ def current_root_task(self) -> Task | None: # Core task handling primitives ################ - @_public # Type-ignore due to use of Any here. - def reschedule( # type: ignore[misc] - self, - task: Task, - next_send: Outcome[Any] = _NO_SEND, - ) -> None: + @_public + def reschedule(self, task: Task, next_send: Outcome[object] = _NO_SEND) -> None: """Reschedule the given task with the given :class:`outcome.Outcome`. @@ -1896,7 +1910,7 @@ async def python_wrapper(orig_coro: Awaitable[RetT]) -> RetT: self.reschedule(task, None) # type: ignore[arg-type] return task - def task_exited(self, task: Task, outcome: Outcome[Any]) -> None: + def task_exited(self, task: Task, outcome: Outcome[object]) -> None: # break parking lots associated with the exiting task if task in GLOBAL_PARKING_LOT_BREAKER: for lot in GLOBAL_PARKING_LOT_BREAKER[task]: @@ -2108,7 +2122,8 @@ def _deliver_ki_cb(self) -> None: # sortedcontainers doesn't have types, and is reportedly very hard to type: # https://github.com/grantjenks/python-sortedcontainers/issues/68 - waiting_for_idle: Any = attrs.Factory(SortedDict) + # Explicit "Any" is not allowed + waiting_for_idle: Any = attrs.Factory(SortedDict) # type: ignore[misc] @_public async def wait_all_tasks_blocked(self, cushion: float = 0.0) -> None: @@ -2409,7 +2424,7 @@ def run( raise AssertionError(runner.main_task_outcome) -def start_guest_run( +def start_guest_run( # type: ignore[misc] async_fn: Callable[..., Awaitable[RetT]], *args: object, run_sync_soon_threadsafe: Callable[[Callable[[], object]], object], @@ -2713,7 +2728,7 @@ def unrolled_run( next_send_fn = task._next_send_fn next_send = task._next_send task._next_send_fn = task._next_send = None - final_outcome: Outcome[Any] | None = None + final_outcome: Outcome[object] | None = None try: # We used to unwrap the Outcome object here and send/throw # its contents in directly, but it turns out that .throw() @@ -2822,15 +2837,15 @@ def unrolled_run( ################################################################ -class _TaskStatusIgnored(TaskStatus[Any]): +class _TaskStatusIgnored(TaskStatus[object]): def __repr__(self) -> str: return "TASK_STATUS_IGNORED" - def started(self, value: Any = None) -> None: + def started(self, value: object = None) -> None: pass -TASK_STATUS_IGNORED: Final[TaskStatus[Any]] = _TaskStatusIgnored() +TASK_STATUS_IGNORED: Final[TaskStatus[object]] = _TaskStatusIgnored() def current_task() -> Task: diff --git a/src/trio/_core/_tests/test_guest_mode.py b/src/trio/_core/_tests/test_guest_mode.py index 5beee4b22..d80479618 100644 --- a/src/trio/_core/_tests/test_guest_mode.py +++ b/src/trio/_core/_tests/test_guest_mode.py @@ -46,13 +46,14 @@ # our main # - final result is returned # - any unhandled exceptions cause an immediate crash -def trivial_guest_run( +# type ignore is for `Explicit "Any" is not allowed` +def trivial_guest_run( # type: ignore[misc] trio_fn: Callable[..., Awaitable[T]], *, in_host_after_start: Callable[[], None] | None = None, **start_guest_run_kwargs: Any, ) -> T: - todo: queue.Queue[tuple[str, Outcome[T] | Callable[..., object]]] = queue.Queue() + todo: queue.Queue[tuple[str, Outcome[T] | Callable[[], object]]] = queue.Queue() host_thread = threading.current_thread() @@ -430,7 +431,8 @@ async def abandoned_main(in_host: InHost) -> None: trio.current_time() -def aiotrio_run( +# Explicit "Any" is not allowed +def aiotrio_run( # type: ignore[misc] trio_fn: Callable[..., Awaitable[T]], *, pass_not_threadsafe: bool = True, @@ -555,7 +557,8 @@ async def crash_in_worker_thread_io(in_host: InHost) -> None: t = threading.current_thread() old_get_events = trio._core._run.TheIOManager.get_events - def bad_get_events(*args: Any) -> object: + # Not allowed to use Any + def bad_get_events(*args: Any) -> object: # type: ignore[misc] if threading.current_thread() is not t: raise ValueError("oh no!") else: diff --git a/src/trio/_core/_tests/test_run.py b/src/trio/_core/_tests/test_run.py index d87bd2102..a9c0e1606 100644 --- a/src/trio/_core/_tests/test_run.py +++ b/src/trio/_core/_tests/test_run.py @@ -1646,7 +1646,10 @@ async def func1(expected: str) -> None: async def func2() -> None: # pragma: no cover pass - async def check(spawn_fn: Callable[..., object]) -> None: + # Explicit "Any" is not allowed + async def check( # type: ignore[misc] + spawn_fn: Callable[..., object], + ) -> None: spawn_fn(func1, "func1") spawn_fn(func1, "func2", name=func2) spawn_fn(func1, "func3", name="func3") @@ -1681,13 +1684,14 @@ async def test_current_effective_deadline(mock_clock: _core.MockClock) -> None: def test_nice_error_on_bad_calls_to_run_or_spawn() -> None: - def bad_call_run( + # Explicit "Any" is not allowed + def bad_call_run( # type: ignore[misc] func: Callable[..., Awaitable[object]], *args: tuple[object, ...], ) -> None: _core.run(func, *args) - def bad_call_spawn( + def bad_call_spawn( # type: ignore[misc] func: Callable[..., Awaitable[object]], *args: tuple[object, ...], ) -> None: @@ -2298,10 +2302,18 @@ async def detachable_coroutine( # is still iterable. At that point anything can be sent into the coroutine, so the .coro type # is wrong. assert pdco_outcome is None - assert not_none(task).coro.send(cast(Any, "be free!")) == "I'm free!" + # Explicit "Any" is not allowed + assert ( + not_none(task).coro.send( + cast(Any, "be free!"), # type: ignore[misc] + ) + == "I'm free!" + ) assert pdco_outcome == outcome.Value("be free!") with pytest.raises(StopIteration): - not_none(task).coro.send(cast(Any, None)) + not_none(task).coro.send( + cast(Any, None), # type: ignore[misc] + ) # Check the exception paths too task = None @@ -2366,9 +2378,25 @@ def abort_fn(_: _core.RaiseCancelT) -> _core.Abort: # pragma: no cover await wait_all_tasks_blocked() # Okay, it's detached. Here's our coroutine runner: - assert not_none(task).coro.send(cast(Any, "not trio!")) == 1 - assert not_none(task).coro.send(cast(Any, None)) == 2 - assert not_none(task).coro.send(cast(Any, None)) == "byebye" + # Explicit "Any" is not allowed + assert ( + not_none(task).coro.send( + cast(Any, "not trio!"), # type: ignore[misc] + ) + == 1 + ) + assert ( + not_none(task).coro.send( + cast(Any, None), # type: ignore[misc] + ) + == 2 + ) + assert ( + not_none(task).coro.send( + cast(Any, None), # type: ignore[misc] + ) + == "byebye" + ) # Now it's been reattached, and we can leave the nursery @@ -2398,7 +2426,9 @@ def abort_fn(_: _core.RaiseCancelT) -> _core.Abort: await wait_all_tasks_blocked() assert task is not None nursery.cancel_scope.cancel() - task.coro.send(cast(Any, None)) + task.coro.send( + cast(Any, None), # type: ignore[misc] + ) assert abort_fn_called diff --git a/src/trio/_core/_thread_cache.py b/src/trio/_core/_thread_cache.py index c61222269..4a4271b0e 100644 --- a/src/trio/_core/_thread_cache.py +++ b/src/trio/_core/_thread_cache.py @@ -208,7 +208,7 @@ def _work(self) -> None: class ThreadCache: def __init__(self) -> None: - self._idle_workers: dict[WorkerThread[Any], None] = {} + self._idle_workers: dict[WorkerThread[Any], None] = {} # type: ignore[misc] def start_thread_soon( self, diff --git a/src/trio/_core/_traps.py b/src/trio/_core/_traps.py index 27518406c..29146b6b4 100644 --- a/src/trio/_core/_traps.py +++ b/src/trio/_core/_traps.py @@ -77,7 +77,10 @@ class WaitTaskRescheduled: # Should always return the type a Task "expects", unless you willfully reschedule it # with a bad value. -async def wait_task_rescheduled(abort_func: Callable[[RaiseCancelT], Abort]) -> Any: +# Explicit "Any" is not allowed +async def wait_task_rescheduled( # type: ignore[misc] + abort_func: Callable[[RaiseCancelT], Abort], +) -> Any: """Put the current task to sleep, with cancellation support. This is the lowest-level API for blocking in Trio. Every time a @@ -182,11 +185,12 @@ def abort(inner_raise_cancel): # Not exported in the trio._core namespace, but imported directly by _run. @attrs.frozen(slots=False) class PermanentlyDetachCoroutineObject: - final_outcome: outcome.Outcome[Any] + final_outcome: outcome.Outcome[object] -async def permanently_detach_coroutine_object( - final_outcome: outcome.Outcome[Any], +# Explicit "Any" is not allowed +async def permanently_detach_coroutine_object( # type: ignore[misc] + final_outcome: outcome.Outcome[object], ) -> Any: """Permanently detach the current task from the Trio scheduler. @@ -220,7 +224,7 @@ async def permanently_detach_coroutine_object( async def temporarily_detach_coroutine_object( abort_func: Callable[[RaiseCancelT], Abort], -) -> Any: +) -> object: """Temporarily detach the current coroutine object from the Trio scheduler. diff --git a/src/trio/_dtls.py b/src/trio/_dtls.py index 11ad2fc5f..c8614a8e8 100644 --- a/src/trio/_dtls.py +++ b/src/trio/_dtls.py @@ -19,7 +19,6 @@ from itertools import count from typing import ( TYPE_CHECKING, - Any, Generic, TypeVar, Union, @@ -40,6 +39,7 @@ from OpenSSL import SSL # noqa: TCH004 from typing_extensions import Self, TypeAlias, TypeVarTuple, Unpack + from trio._socket import AddressFormat from trio.socket import SocketType PosArgsT = TypeVarTuple("PosArgsT") @@ -568,7 +568,7 @@ def _make_cookie( key: bytes, salt: bytes, tick: int, - address: Any, + address: AddressFormat, client_hello_bits: bytes, ) -> bytes: assert len(salt) == SALT_BYTES @@ -589,7 +589,7 @@ def _make_cookie( def valid_cookie( key: bytes, cookie: bytes, - address: Any, + address: AddressFormat, client_hello_bits: bytes, ) -> bool: if len(cookie) > SALT_BYTES: @@ -618,7 +618,7 @@ def valid_cookie( def challenge_for( key: bytes, - address: Any, + address: AddressFormat, epoch_seqno: int, client_hello_bits: bytes, ) -> bytes: @@ -682,7 +682,7 @@ def _read_loop(read_fn: Callable[[int], bytes]) -> bytes: async def handle_client_hello_untrusted( endpoint: DTLSEndpoint, - address: Any, + address: AddressFormat, packet: bytes, ) -> None: # it's trivial to write a simple function that directly calls this to @@ -843,7 +843,7 @@ class DTLSChannel(trio.abc.Channel[bytes], metaclass=NoPublicConstructor): def __init__( self, endpoint: DTLSEndpoint, - peer_address: Any, + peer_address: AddressFormat, ctx: SSL.Context, ) -> None: self.endpoint = endpoint @@ -1219,7 +1219,9 @@ def __init__( # as a peer provides a valid cookie, we can immediately tear down the # old connection. # {remote address: DTLSChannel} - self._streams: WeakValueDictionary[Any, DTLSChannel] = WeakValueDictionary() + self._streams: WeakValueDictionary[AddressFormat, DTLSChannel] = ( + WeakValueDictionary() + ) self._listening_context: SSL.Context | None = None self._listening_key: bytes | None = None self._incoming_connections_q = _Queue[DTLSChannel](float("inf")) diff --git a/src/trio/_file_io.py b/src/trio/_file_io.py index 76c17086d..50478af62 100644 --- a/src/trio/_file_io.py +++ b/src/trio/_file_io.py @@ -435,7 +435,8 @@ async def open_file( # type: ignore[misc] # Any usage matches builtins.open(). ) -> AsyncIOWrapper[IO[Any]]: ... -async def open_file( +# Explicit "Any" is not allowed +async def open_file( # type: ignore[misc] file: _OpenFile, mode: str = "r", buffering: int = -1, diff --git a/src/trio/_highlevel_open_tcp_stream.py b/src/trio/_highlevel_open_tcp_stream.py index 1e7f4332d..d4ec98355 100644 --- a/src/trio/_highlevel_open_tcp_stream.py +++ b/src/trio/_highlevel_open_tcp_stream.py @@ -11,6 +11,8 @@ from collections.abc import Generator from socket import AddressFamily, SocketKind + from trio._socket import AddressFormat + if sys.version_info < (3, 11): from exceptiongroup import BaseExceptionGroup, ExceptionGroup @@ -132,16 +134,9 @@ def close_all() -> Generator[set[SocketType], None, None]: raise BaseExceptionGroup("", errs) -def reorder_for_rfc_6555_section_5_4( - targets: list[ - tuple[ - AddressFamily, - SocketKind, - int, - str, - Any, - ] - ], +# Explicit "Any" is not allowed +def reorder_for_rfc_6555_section_5_4( # type: ignore[misc] + targets: list[tuple[AddressFamily, SocketKind, int, str, Any]], ) -> None: # RFC 6555 section 5.4 says that if getaddrinfo returns multiple address # families (e.g. IPv4 and IPv6), then you should make sure that your first @@ -302,7 +297,7 @@ async def open_tcp_stream( # face of crash or cancellation async def attempt_connect( socket_args: tuple[AddressFamily, SocketKind, int], - sockaddr: Any, + sockaddr: AddressFormat, attempt_failed: trio.Event, ) -> None: nonlocal winning_socket diff --git a/src/trio/_highlevel_serve_listeners.py b/src/trio/_highlevel_serve_listeners.py index 0a85c8ecb..9b17f8d53 100644 --- a/src/trio/_highlevel_serve_listeners.py +++ b/src/trio/_highlevel_serve_listeners.py @@ -25,7 +25,8 @@ StreamT = TypeVar("StreamT", bound=trio.abc.AsyncResource) -ListenerT = TypeVar("ListenerT", bound=trio.abc.Listener[Any]) +# Explicit "Any" is not allowed +ListenerT = TypeVar("ListenerT", bound=trio.abc.Listener[Any]) # type: ignore[misc] Handler = Callable[[StreamT], Awaitable[object]] @@ -67,7 +68,8 @@ async def _serve_one_listener( # https://github.com/python/typing/issues/548 -async def serve_listeners( +# Explicit "Any" is not allowed +async def serve_listeners( # type: ignore[misc] handler: Handler[StreamT], listeners: list[ListenerT], *, diff --git a/src/trio/_path.py b/src/trio/_path.py index 2c9dfff29..4e52fec24 100644 --- a/src/trio/_path.py +++ b/src/trio/_path.py @@ -30,7 +30,8 @@ T = TypeVar("T") -def _wraps_async( +# Explicit "Any" is not allowed +def _wraps_async( # type: ignore[misc] wrapped: Callable[..., Any], ) -> Callable[[Callable[P, T]], Callable[P, Awaitable[T]]]: def decorator(fn: Callable[P, T]) -> Callable[P, Awaitable[T]]: diff --git a/src/trio/_socket.py b/src/trio/_socket.py index b137a4e02..d40309cd3 100644 --- a/src/trio/_socket.py +++ b/src/trio/_socket.py @@ -50,7 +50,8 @@ # most users, so currently we just specify it as `Any`. Otherwise we would write: # `AddressFormat = TypeVar("AddressFormat")` # but instead we simply do: -AddressFormat: TypeAlias = Any +# Explicit "Any" is not allowed +AddressFormat: TypeAlias = Any # type: ignore[misc] # Usage: @@ -477,7 +478,7 @@ async def _resolve_address_nocp( ipv6_v6only: bool | int, address: AddressFormat, local: bool, -) -> Any: +) -> AddressFormat: # Do some pre-checking (or exit early for non-IP sockets) if family == _stdlib_socket.AF_INET: if not isinstance(address, tuple) or not len(address) == 2: @@ -709,7 +710,8 @@ def recvfrom_into( not TYPE_CHECKING and hasattr(_stdlib_socket.socket, "recvmsg") ): - def recvmsg( + # Explicit "Any" is not allowed + def recvmsg( # type: ignore[misc] __self, __bufsize: int, __ancbufsize: int = 0, @@ -721,7 +723,8 @@ def recvmsg( not TYPE_CHECKING and hasattr(_stdlib_socket.socket, "recvmsg_into") ): - def recvmsg_into( + # Explicit "Any" is not allowed + def recvmsg_into( # type: ignore[misc] __self, __buffers: Iterable[Buffer], __ancbufsize: int = 0, @@ -747,7 +750,8 @@ async def sendto( __address: tuple[object, ...] | str | Buffer, ) -> int: ... - async def sendto(self, *args: Any) -> int: + # Explicit "Any" is not allowed + async def sendto(self, *args: Any) -> int: # type: ignore[misc] raise NotImplementedError if sys.platform != "win32" or ( @@ -1190,7 +1194,8 @@ def recvfrom_into( ): if TYPE_CHECKING: - def recvmsg( + # Explicit "Any" is not allowed + def recvmsg( # type: ignore[misc] __self, __bufsize: int, __ancbufsize: int = 0, @@ -1212,7 +1217,8 @@ def recvmsg( ): if TYPE_CHECKING: - def recvmsg_into( + # Explicit "Any" is not allowed + def recvmsg_into( # type: ignore[misc] __self, __buffers: Iterable[Buffer], __ancbufsize: int = 0, diff --git a/src/trio/_ssl.py b/src/trio/_ssl.py index df1cbc37b..46ab0776e 100644 --- a/src/trio/_ssl.py +++ b/src/trio/_ssl.py @@ -219,7 +219,12 @@ class NeedHandshakeError(Exception): class _Once: - def __init__(self, afn: Callable[..., Awaitable[object]], *args: object) -> None: + # Explicit "Any" is not allowed + def __init__( # type: ignore[misc] + self, + afn: Callable[..., Awaitable[object]], + *args: object, + ) -> None: self._afn = afn self._args = args self.started = False @@ -413,7 +418,11 @@ def __init__( "version", } - def __getattr__(self, name: str) -> Any: + # Explicit "Any" is not allowed + def __getattr__( # type: ignore[misc] + self, + name: str, + ) -> Any: if name in self._forwarded: if name in self._after_handshake and not self._handshook.done: raise NeedHandshakeError(f"call do_handshake() before calling {name!r}") @@ -445,7 +454,8 @@ def _check_status(self) -> None: # comments, though, just make sure to think carefully if you ever have to # touch it. The big comment at the top of this file will help explain # too. - async def _retry( + # Explicit "Any" is not allowed + async def _retry( # type: ignore[misc] self, fn: Callable[..., T], *args: object, diff --git a/src/trio/_tests/test_deprecate_strict_exception_groups_false.py b/src/trio/_tests/test_deprecate_strict_exception_groups_false.py index 7e575aa92..1b02c9ee7 100644 --- a/src/trio/_tests/test_deprecate_strict_exception_groups_false.py +++ b/src/trio/_tests/test_deprecate_strict_exception_groups_false.py @@ -32,7 +32,7 @@ async def foo_loose_nursery() -> None: async with trio.open_nursery(strict_exception_groups=False): ... - def helper(fun: Callable[..., Awaitable[None]], num: int) -> None: + def helper(fun: Callable[[], Awaitable[None]], num: int) -> None: with pytest.warns( trio.TrioDeprecationWarning, match="strict_exception_groups=False", diff --git a/src/trio/_tests/test_highlevel_open_tcp_listeners.py b/src/trio/_tests/test_highlevel_open_tcp_listeners.py index 30596aa4f..734427a53 100644 --- a/src/trio/_tests/test_highlevel_open_tcp_listeners.py +++ b/src/trio/_tests/test_highlevel_open_tcp_listeners.py @@ -4,7 +4,7 @@ import socket as stdlib_socket import sys from socket import AddressFamily, SocketKind -from typing import TYPE_CHECKING, Any, overload +from typing import TYPE_CHECKING, overload import attrs import pytest @@ -30,6 +30,8 @@ from typing_extensions import Buffer + from trio._socket import AddressFormat + async def test_open_tcp_listeners_basic() -> None: listeners = await open_tcp_listeners(0) @@ -195,7 +197,10 @@ def setsockopt( ) -> None: pass - async def bind(self, address: Any) -> None: + async def bind( + self, + address: AddressFormat, + ) -> None: pass def listen(self, /, backlog: int = min(stdlib_socket.SOMAXCONN, 128)) -> None: diff --git a/src/trio/_tests/test_highlevel_open_tcp_stream.py b/src/trio/_tests/test_highlevel_open_tcp_stream.py index 0032a551d..98adf7efe 100644 --- a/src/trio/_tests/test_highlevel_open_tcp_stream.py +++ b/src/trio/_tests/test_highlevel_open_tcp_stream.py @@ -3,7 +3,7 @@ import socket import sys from socket import AddressFamily, SocketKind -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING import attrs import pytest @@ -360,7 +360,8 @@ async def run_scenario( # If this is True, we require there to be an exception, and return # (exception, scenario object) expect_error: tuple[type[BaseException], ...] | type[BaseException] = (), - **kwargs: Any, + happy_eyeballs_delay: float | None = 0.25, + local_address: str | None = None, ) -> tuple[SocketType, Scenario] | tuple[BaseException, Scenario]: supported_families = set() if ipv4_supported: @@ -372,7 +373,12 @@ async def run_scenario( trio.socket.set_custom_socket_factory(scenario) try: - stream = await open_tcp_stream("test.example.com", port, **kwargs) + stream = await open_tcp_stream( + "test.example.com", + port, + happy_eyeballs_delay=happy_eyeballs_delay, + local_address=local_address, + ) assert expect_error == () scenario.check(stream.socket) return (stream.socket, scenario) diff --git a/src/trio/_tests/test_highlevel_ssl_helpers.py b/src/trio/_tests/test_highlevel_ssl_helpers.py index ca23c333c..340264a2c 100644 --- a/src/trio/_tests/test_highlevel_ssl_helpers.py +++ b/src/trio/_tests/test_highlevel_ssl_helpers.py @@ -66,7 +66,11 @@ async def getaddrinfo( ]: return [(AF_INET, SOCK_STREAM, IPPROTO_TCP, "", self.sockaddr)] - async def getnameinfo(self, *args: Any) -> NoReturn: # pragma: no cover + # Explicit "Any" is not allowed + async def getnameinfo( # type: ignore[misc] + self, + *args: Any, + ) -> NoReturn: # pragma: no cover raise NotImplementedError diff --git a/src/trio/_tests/test_socket.py b/src/trio/_tests/test_socket.py index 68040cebf..bdd5936fa 100644 --- a/src/trio/_tests/test_socket.py +++ b/src/trio/_tests/test_socket.py @@ -41,13 +41,22 @@ class MonkeypatchedGAI: - def __init__(self, orig_getaddrinfo: Callable[..., GetAddrInfoResponse]) -> None: + # Explicit "Any" is not allowed + def __init__( # type: ignore[misc] + self, + orig_getaddrinfo: Callable[..., GetAddrInfoResponse], + ) -> None: self._orig_getaddrinfo = orig_getaddrinfo - self._responses: dict[tuple[Any, ...], GetAddrInfoResponse | str] = {} - self.record: list[tuple[Any, ...]] = [] + self._responses: dict[tuple[Any, ...], GetAddrInfoResponse | str] = {} # type: ignore[misc] + self.record: list[tuple[Any, ...]] = [] # type: ignore[misc] # get a normalized getaddrinfo argument tuple - def _frozenbind(self, *args: Any, **kwargs: Any) -> tuple[Any, ...]: + # Explicit "Any" is not allowed + def _frozenbind( # type: ignore[misc] + self, + *args: Any, + **kwargs: Any, + ) -> tuple[Any, ...]: sig = inspect.signature(self._orig_getaddrinfo) bound = sig.bind(*args, **kwargs) bound.apply_defaults() @@ -55,7 +64,8 @@ def _frozenbind(self, *args: Any, **kwargs: Any) -> tuple[Any, ...]: assert not bound.kwargs return frozenbound - def set( + # Explicit "Any" is not allowed + def set( # type: ignore[misc] self, response: GetAddrInfoResponse | str, *args: Any, @@ -63,7 +73,12 @@ def set( ) -> None: self._responses[self._frozenbind(*args, **kwargs)] = response - def getaddrinfo(self, *args: Any, **kwargs: Any) -> GetAddrInfoResponse | str: + # Explicit "Any" is not allowed + def getaddrinfo( # type: ignore[misc] + self, + *args: Any, + **kwargs: Any, + ) -> GetAddrInfoResponse | str: bound = self._frozenbind(*args, **kwargs) self.record.append(bound) if bound in self._responses: @@ -586,7 +601,8 @@ def assert_eq( # local=True/local=False should work the same: for local in [False, True]: - async def res( + # Explicit "Any" is not allowed + async def res( # type: ignore[misc] args: ( tuple[str, int] | tuple[str, int, int] @@ -794,7 +810,12 @@ async def test_SocketType_connect_paths() -> None: # nose -- and then swap it back out again before we hit # wait_socket_writable, which insists on a real socket. class CancelSocket(stdlib_socket.socket): - def connect(self, *args: Any, **kwargs: Any) -> None: + # Explicit "Any" is not allowed + def connect( # type: ignore[misc] + self, + *args: Any, + **kwargs: Any, + ) -> None: # accessing private method only available in _SocketType assert isinstance(sock, _SocketType) @@ -850,8 +871,9 @@ async def test_resolve_address_exception_in_connect_closes_socket() -> None: with _core.CancelScope() as cancel_scope: with tsocket.socket() as sock: - async def _resolve_address_nocp( - self: Any, + # Explicit "Any" is not allowed + async def _resolve_address_nocp( # type: ignore[misc] + self: _SocketType, *args: Any, **kwargs: Any, ) -> None: @@ -918,6 +940,7 @@ async def test_send_recv_variants() -> None: # recvfrom_into assert await a.sendto(b"xxx", b.getsockname()) == 3 buf = bytearray(10) + nbytes: int (nbytes, addr) = await b.recvfrom_into(buf) assert nbytes == 3 assert buf == b"xxx" + b"\x00" * 7 diff --git a/src/trio/_tests/test_ssl.py b/src/trio/_tests/test_ssl.py index 9926abff0..f96a4feca 100644 --- a/src/trio/_tests/test_ssl.py +++ b/src/trio/_tests/test_ssl.py @@ -393,7 +393,8 @@ def virtual_ssl_echo_server( yield SSLStream(fakesock, client_ctx, server_hostname="trio-test-1.example.org") -def ssl_wrap_pair( +# Explicit "Any" is not allowed +def ssl_wrap_pair( # type: ignore[misc] client_ctx: SSLContext, client_transport: T_Stream, server_transport: T_Stream, @@ -423,7 +424,11 @@ def ssl_wrap_pair( MemoryStapledStream: TypeAlias = StapledStream[MemorySendStream, MemoryReceiveStream] -def ssl_memory_stream_pair(client_ctx: SSLContext, **kwargs: Any) -> tuple[ +# Explicit "Any" is not allowed +def ssl_memory_stream_pair( # type: ignore[misc] + client_ctx: SSLContext, + **kwargs: Any, +) -> tuple[ SSLStream[MemoryStapledStream], SSLStream[MemoryStapledStream], ]: @@ -434,7 +439,11 @@ def ssl_memory_stream_pair(client_ctx: SSLContext, **kwargs: Any) -> tuple[ MyStapledStream: TypeAlias = StapledStream[SendStream, ReceiveStream] -def ssl_lockstep_stream_pair(client_ctx: SSLContext, **kwargs: Any) -> tuple[ +# Explicit "Any" is not allowed +def ssl_lockstep_stream_pair( # type: ignore[misc] + client_ctx: SSLContext, + **kwargs: Any, +) -> tuple[ SSLStream[MyStapledStream], SSLStream[MyStapledStream], ]: @@ -1318,7 +1327,8 @@ async def test_getpeercert(client_ctx: SSLContext) -> None: async def test_SSLListener(client_ctx: SSLContext) -> None: - async def setup( + # Explicit "Any" is not allowed + async def setup( # type: ignore[misc] **kwargs: Any, ) -> tuple[tsocket.SocketType, SSLListener[SocketStream], SSLStream[SocketStream]]: listen_sock = tsocket.socket() diff --git a/src/trio/_tests/test_subprocess.py b/src/trio/_tests/test_subprocess.py index 4a870ed7a..8c8d0faba 100644 --- a/src/trio/_tests/test_subprocess.py +++ b/src/trio/_tests/test_subprocess.py @@ -113,7 +113,11 @@ async def run_process_in_nursery(*args: Any, **kwargs: Any) -> AsyncIterator[Pro ids=["open_process", "run_process in nursery"], ) -BackgroundProcessType: TypeAlias = Callable[..., AbstractAsyncContextManager[Process]] +# Explicit "Any" is not allowed +BackgroundProcessType: TypeAlias = Callable[ # type: ignore[misc] + ..., + AbstractAsyncContextManager[Process], +] @background_process_param diff --git a/src/trio/_tests/test_testing_raisesgroup.py b/src/trio/_tests/test_testing_raisesgroup.py index 17eb6afcc..d0e89c22d 100644 --- a/src/trio/_tests/test_testing_raisesgroup.py +++ b/src/trio/_tests/test_testing_raisesgroup.py @@ -235,7 +235,11 @@ def test_RaisesGroup_matches() -> None: def test_message() -> None: - def check_message(message: str, body: RaisesGroup[Any]) -> None: + # Explicit "Any" is not allowed + def check_message( # type: ignore[misc] + message: str, + body: RaisesGroup[Any], + ) -> None: with pytest.raises( AssertionError, match=f"^DID NOT RAISE any exception, expected {re.escape(message)}$", diff --git a/src/trio/_tests/test_threads.py b/src/trio/_tests/test_threads.py index df9d2e74a..641454d2e 100644 --- a/src/trio/_tests/test_threads.py +++ b/src/trio/_tests/test_threads.py @@ -55,7 +55,8 @@ async def test_do_in_trio_thread() -> None: trio_thread = threading.current_thread() - async def check_case( + # Explicit "Any" is not allowed + async def check_case( # type: ignore[misc] do_in_trio_thread: Callable[..., threading.Thread], fn: Callable[..., T | Awaitable[T]], expected: tuple[str, T], diff --git a/src/trio/_tests/test_util.py b/src/trio/_tests/test_util.py index 41ce5f27c..68f9026e2 100644 --- a/src/trio/_tests/test_util.py +++ b/src/trio/_tests/test_util.py @@ -1,7 +1,9 @@ +from __future__ import annotations + import signal import sys import types -from typing import Any, TypeVar +from typing import TYPE_CHECKING, Any, TypeVar import pytest @@ -25,6 +27,9 @@ ) from ..testing import wait_all_tasks_blocked +if TYPE_CHECKING: + from collections.abc import AsyncGenerator + T = TypeVar("T") @@ -147,12 +152,13 @@ def generator_based_coro() -> Any: # pragma: no cover assert "appears to be synchronous" in str(excinfo.value) - async def async_gen(_: object) -> Any: # pragma: no cover + async def async_gen( + _: object, + ) -> AsyncGenerator[None, None]: # pragma: no cover yield - # does not give arg-type typing error with pytest.raises(TypeError) as excinfo: - coroutine_or_error(async_gen, [0]) # type: ignore[unused-coroutine] + coroutine_or_error(async_gen, [0]) # type: ignore[arg-type,unused-coroutine] msg = "expected an async function but got an async generator" assert msg in str(excinfo.value) diff --git a/src/trio/_threads.py b/src/trio/_threads.py index 4cd460078..2741f1a6f 100644 --- a/src/trio/_threads.py +++ b/src/trio/_threads.py @@ -146,8 +146,10 @@ class ThreadPlaceholder: # Types for the to_thread_run_sync message loop @attrs.frozen(eq=False, slots=False) -class Run(Generic[RetT]): - afn: Callable[..., Awaitable[RetT]] +# Explicit "Any" is not allowed +class Run(Generic[RetT]): # type: ignore[misc] + # Explicit "Any" is not allowed + afn: Callable[..., Awaitable[RetT]] # type: ignore[misc] args: tuple[object, ...] context: contextvars.Context = attrs.field( init=False, @@ -205,8 +207,10 @@ def in_trio_thread() -> None: @attrs.frozen(eq=False, slots=False) -class RunSync(Generic[RetT]): - fn: Callable[..., RetT] +# Explicit "Any" is not allowed +class RunSync(Generic[RetT]): # type: ignore[misc] + # Explicit "Any" is not allowed + fn: Callable[..., RetT] # type: ignore[misc] args: tuple[object, ...] context: contextvars.Context = attrs.field( init=False, @@ -522,7 +526,8 @@ def _send_message_to_trio( return message_to_trio.queue.get().unwrap() -def from_thread_run( +# Explicit "Any" is not allowed +def from_thread_run( # type: ignore[misc] afn: Callable[..., Awaitable[RetT]], *args: object, trio_token: TrioToken | None = None, @@ -566,7 +571,8 @@ def from_thread_run( return _send_message_to_trio(trio_token, Run(afn, args)) -def from_thread_run_sync( +# Explicit "Any" is not allowed +def from_thread_run_sync( # type: ignore[misc] fn: Callable[..., RetT], *args: object, trio_token: TrioToken | None = None, diff --git a/src/trio/_tools/mypy_annotate.py b/src/trio/_tools/mypy_annotate.py index 5acb9b993..bdce508ff 100644 --- a/src/trio/_tools/mypy_annotate.py +++ b/src/trio/_tools/mypy_annotate.py @@ -74,7 +74,7 @@ def export(results: dict[Result, list[str]]) -> None: print(f"col={res.start_col},", end="") if res.end_col is not None and res.end_line is not None: print(f"endLine={res.end_line},endColumn={res.end_col},", end="") - message = f"({res.start_line}:{res.start_col} - {res.end_line}:{res.end_col}):{res.message}" + message = f"({res.start_line}:{res.start_col}:{res.end_line}:{res.end_col}):{res.message}" else: message = f"({res.start_line}:{res.start_col}):{res.message}" else: diff --git a/src/trio/_util.py b/src/trio/_util.py index e7c15b5da..9b49e3bfa 100644 --- a/src/trio/_util.py +++ b/src/trio/_util.py @@ -22,7 +22,8 @@ import trio -CallT = TypeVar("CallT", bound=Callable[..., Any]) +# Explicit "Any" is not allowed +CallT = TypeVar("CallT", bound=Callable[..., Any]) # type: ignore[misc] T = TypeVar("T") RetT = TypeVar("RetT") @@ -232,14 +233,16 @@ def __exit__( self._held = False -def async_wraps( +# Explicit "Any" is not allowed +def async_wraps( # type: ignore[misc] cls: type[object], wrapped_cls: type[object], attr_name: str, ) -> Callable[[CallT], CallT]: """Similar to wraps, but for async wrappers of non-async functions.""" - def decorator(func: CallT) -> CallT: + # Explicit "Any" is not allowed + def decorator(func: CallT) -> CallT: # type: ignore[misc] func.__name__ = attr_name func.__qualname__ = f"{cls.__qualname__}.{attr_name}" @@ -302,11 +305,15 @@ def open_memory_channel(max_buffer_size: int) -> Tuple[ but at least it becomes possible to write those. """ - def __init__(self, fn: Callable[..., RetT]) -> None: + # Explicit "Any" is not allowed + def __init__( # type: ignore[misc] + self, + fn: Callable[..., RetT], + ) -> None: update_wrapper(self, fn) self._fn = fn - def __call__(self, *args: Any, **kwargs: Any) -> RetT: + def __call__(self, *args: object, **kwargs: object) -> RetT: return self._fn(*args, **kwargs) def __getitem__(self, subscript: object) -> Self: @@ -395,9 +402,11 @@ def name_asyncgen(agen: AsyncGeneratorType[object, NoReturn]) -> str: # work around a pyright error if TYPE_CHECKING: - Fn = TypeVar("Fn", bound=Callable[..., object]) + # Explicit "Any" is not allowed + Fn = TypeVar("Fn", bound=Callable[..., object]) # type: ignore[misc] - def wraps( + # Explicit "Any" is not allowed + def wraps( # type: ignore[misc] wrapped: Callable[..., object], assigned: Sequence[str] = ..., updated: Sequence[str] = ..., diff --git a/src/trio/testing/_fake_net.py b/src/trio/testing/_fake_net.py index 749bedf8d..e5a4b41bb 100644 --- a/src/trio/testing/_fake_net.py +++ b/src/trio/testing/_fake_net.py @@ -36,6 +36,8 @@ from typing_extensions import Buffer, Self, TypeAlias + from trio._socket import AddressFormat + IPAddress: TypeAlias = Union[ipaddress.IPv4Address, ipaddress.IPv6Address] @@ -313,7 +315,7 @@ async def _sendmsg( buffers: Iterable[Buffer], ancdata: Iterable[tuple[int, int, Buffer]] = (), flags: int = 0, - address: Any | None = None, + address: AddressFormat | None = None, ) -> int: self._check_closed() @@ -357,7 +359,12 @@ async def _recvmsg_into( buffers: Iterable[Buffer], ancbufsize: int = 0, flags: int = 0, - ) -> tuple[int, list[tuple[int, int, bytes]], int, Any]: + ) -> tuple[ + int, + list[tuple[int, int, bytes]], + int, + tuple[str, int] | tuple[str, int, int, int], + ]: if ancbufsize != 0: raise NotImplementedError("FakeNet doesn't support ancillary data") if flags != 0: @@ -500,7 +507,11 @@ async def sendto( __address: tuple[object, ...] | str | None | Buffer, ) -> int: ... - async def sendto(self, *args: Any) -> int: + # Explicit "Any" is not allowed + async def sendto( # type: ignore[misc] + self, + *args: Any, + ) -> int: data: Buffer flags: int address: tuple[object, ...] | str | Buffer @@ -521,7 +532,11 @@ async def recv_into(self, buf: Buffer, nbytes: int = 0, flags: int = 0) -> int: got_bytes, _address = await self.recvfrom_into(buf, nbytes, flags) return got_bytes - async def recvfrom(self, bufsize: int, flags: int = 0) -> tuple[bytes, Any]: + async def recvfrom( + self, + bufsize: int, + flags: int = 0, + ) -> tuple[bytes, AddressFormat]: data, _ancdata, _msg_flags, address = await self._recvmsg(bufsize, flags) return data, address @@ -530,7 +545,7 @@ async def recvfrom_into( buf: Buffer, nbytes: int = 0, flags: int = 0, - ) -> tuple[int, Any]: + ) -> tuple[int, AddressFormat]: if nbytes != 0 and nbytes != memoryview(buf).nbytes: raise NotImplementedError("partial recvfrom_into") got_nbytes, _ancdata, _msg_flags, address = await self._recvmsg_into( @@ -545,7 +560,7 @@ async def _recvmsg( bufsize: int, ancbufsize: int = 0, flags: int = 0, - ) -> tuple[bytes, list[tuple[int, int, bytes]], int, Any]: + ) -> tuple[bytes, list[tuple[int, int, bytes]], int, AddressFormat]: buf = bytearray(bufsize) got_nbytes, ancdata, msg_flags, address = await self._recvmsg_into( [buf], diff --git a/test-requirements.in b/test-requirements.in index add7798d0..8a06946cb 100644 --- a/test-requirements.in +++ b/test-requirements.in @@ -11,7 +11,7 @@ cryptography>=41.0.0 # cryptography<41 segfaults on pypy3.10 # Tools black; implementation_name == "cpython" -mypy +mypy[faster-cache] ruff >= 0.6.6 astor # code generation uv >= 0.2.24 diff --git a/test-requirements.txt b/test-requirements.txt index 314eaf4b9..ccacf90a7 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -71,7 +71,7 @@ markupsafe==2.1.5 # via jinja2 mccabe==0.7.0 # via pylint -mypy==1.11.2 +mypy==1.13.0 # via -r test-requirements.in mypy-extensions==1.0.0 # via @@ -80,6 +80,8 @@ mypy-extensions==1.0.0 # mypy nodeenv==1.9.1 # via pyright +orjson==3.10.10 + # via mypy outcome==1.3.0.post0 # via -r test-requirements.in packaging==24.1 From feeccf1c6a05110cf9f1b3bfabc48b8684355707 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Sun, 27 Oct 2024 01:36:32 -0500 Subject: [PATCH 15/52] Fix various things after reviewing all changes --- src/trio/_core/_instrumentation.py | 4 ++-- src/trio/_core/_run.py | 8 +++----- src/trio/_core/_tests/test_guest_mode.py | 4 ++-- src/trio/_core/_thread_cache.py | 1 + src/trio/_tests/test_socket.py | 1 - src/trio/_tools/mypy_annotate.py | 2 +- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/trio/_core/_instrumentation.py b/src/trio/_core/_instrumentation.py index ea807fe4d..bbb2ba2cc 100644 --- a/src/trio/_core/_instrumentation.py +++ b/src/trio/_core/_instrumentation.py @@ -3,7 +3,7 @@ import logging import types from collections.abc import Callable, Sequence -from typing import Any, TypeVar +from typing import TypeVar from .._abc import Instrument @@ -12,7 +12,7 @@ # Explicit "Any" is not allowed -F = TypeVar("F", bound=Callable[..., Any]) # type: ignore[misc] +F = TypeVar("F", bound=Callable[..., object]) # type: ignore[misc] # Decorator to mark methods public. This does nothing by itself, but diff --git a/src/trio/_core/_run.py b/src/trio/_core/_run.py index 4cdcfbf77..51d8c9899 100644 --- a/src/trio/_core/_run.py +++ b/src/trio/_core/_run.py @@ -90,8 +90,7 @@ DEADLINE_HEAP_MIN_PRUNE_THRESHOLD: Final = 1000 # Passed as a sentinel -# Explicit "Any" is not allowed -_NO_SEND: Final[Outcome[Any]] = cast("Outcome[Any]", object()) # type: ignore[misc] +_NO_SEND: Final[Outcome[object]] = cast("Outcome[object]", object()) # Used to track if an exceptiongroup can be collapsed NONSTRICT_EXCEPTIONGROUP_NOTE = 'This is a "loose" ExceptionGroup, and may be collapsed by Trio if it only contains one exception - typically after `Cancelled` has been stripped from it. Note this has consequences for exception handling, and strict_exception_groups=True is recommended.' @@ -1175,11 +1174,10 @@ def _check_nursery_closed(self) -> None: self._parent_waiting_in_aexit = False GLOBAL_RUN_CONTEXT.runner.reschedule(self._parent_task) - # Explicit "Any" is not allowed - def _child_finished( # type: ignore[misc] + def _child_finished( self, task: Task, - outcome: Outcome[Any], + outcome: Outcome[object], ) -> None: self._children.remove(task) if isinstance(outcome, Error): diff --git a/src/trio/_core/_tests/test_guest_mode.py b/src/trio/_core/_tests/test_guest_mode.py index d80479618..2284ec01c 100644 --- a/src/trio/_core/_tests/test_guest_mode.py +++ b/src/trio/_core/_tests/test_guest_mode.py @@ -46,7 +46,7 @@ # our main # - final result is returned # - any unhandled exceptions cause an immediate crash -# type ignore is for `Explicit "Any" is not allowed` +# Explicit "Any" is not allowed def trivial_guest_run( # type: ignore[misc] trio_fn: Callable[..., Awaitable[T]], *, @@ -557,7 +557,7 @@ async def crash_in_worker_thread_io(in_host: InHost) -> None: t = threading.current_thread() old_get_events = trio._core._run.TheIOManager.get_events - # Not allowed to use Any + # Explicit "Any" is not allowed def bad_get_events(*args: Any) -> object: # type: ignore[misc] if threading.current_thread() is not t: raise ValueError("oh no!") diff --git a/src/trio/_core/_thread_cache.py b/src/trio/_core/_thread_cache.py index 4a4271b0e..9dffe898e 100644 --- a/src/trio/_core/_thread_cache.py +++ b/src/trio/_core/_thread_cache.py @@ -208,6 +208,7 @@ def _work(self) -> None: class ThreadCache: def __init__(self) -> None: + # Explicit "Any" is not allowed self._idle_workers: dict[WorkerThread[Any], None] = {} # type: ignore[misc] def start_thread_soon( diff --git a/src/trio/_tests/test_socket.py b/src/trio/_tests/test_socket.py index bdd5936fa..df7f5b33b 100644 --- a/src/trio/_tests/test_socket.py +++ b/src/trio/_tests/test_socket.py @@ -940,7 +940,6 @@ async def test_send_recv_variants() -> None: # recvfrom_into assert await a.sendto(b"xxx", b.getsockname()) == 3 buf = bytearray(10) - nbytes: int (nbytes, addr) = await b.recvfrom_into(buf) assert nbytes == 3 assert buf == b"xxx" + b"\x00" * 7 diff --git a/src/trio/_tools/mypy_annotate.py b/src/trio/_tools/mypy_annotate.py index bdce508ff..5acb9b993 100644 --- a/src/trio/_tools/mypy_annotate.py +++ b/src/trio/_tools/mypy_annotate.py @@ -74,7 +74,7 @@ def export(results: dict[Result, list[str]]) -> None: print(f"col={res.start_col},", end="") if res.end_col is not None and res.end_line is not None: print(f"endLine={res.end_line},endColumn={res.end_col},", end="") - message = f"({res.start_line}:{res.start_col}:{res.end_line}:{res.end_col}):{res.message}" + message = f"({res.start_line}:{res.start_col} - {res.end_line}:{res.end_col}):{res.message}" else: message = f"({res.start_line}:{res.start_col}):{res.message}" else: From 569bc37cbf2da27664b98dc77cf4ec63f6025d24 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Sun, 27 Oct 2024 01:43:20 -0500 Subject: [PATCH 16/52] Do not use faster mypy cache on pypy --- test-requirements.in | 3 ++- test-requirements.txt | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test-requirements.in b/test-requirements.in index 8a06946cb..1c30d8982 100644 --- a/test-requirements.in +++ b/test-requirements.in @@ -11,7 +11,8 @@ cryptography>=41.0.0 # cryptography<41 segfaults on pypy3.10 # Tools black; implementation_name == "cpython" -mypy[faster-cache] +mypy # Would use mypy[faster-cache], but orjson has build issues on pypy +orjson; implementation_name == "cpython" ruff >= 0.6.6 astor # code generation uv >= 0.2.24 diff --git a/test-requirements.txt b/test-requirements.txt index ccacf90a7..0762a82f3 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -80,8 +80,8 @@ mypy-extensions==1.0.0 # mypy nodeenv==1.9.1 # via pyright -orjson==3.10.10 - # via mypy +orjson==3.10.10 ; implementation_name == 'cpython' + # via -r test-requirements.in outcome==1.3.0.post0 # via -r test-requirements.in packaging==24.1 From 521c1b719a9e608851e83b0549e978cc8563fc5d Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Sun, 27 Oct 2024 16:56:07 -0500 Subject: [PATCH 17/52] Try to get rid of more `Any`s --- src/trio/_core/_concat_tb.py | 7 +++---- src/trio/_core/_run.py | 17 +++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/trio/_core/_concat_tb.py b/src/trio/_core/_concat_tb.py index ed785cb64..1334741c0 100644 --- a/src/trio/_core/_concat_tb.py +++ b/src/trio/_core/_concat_tb.py @@ -1,7 +1,7 @@ from __future__ import annotations from types import TracebackType -from typing import Any, ClassVar, cast +from typing import ClassVar, cast ################################################################ # concat_tb @@ -86,10 +86,9 @@ def copy_tb(base_tb: TracebackType, tb_next: TracebackType | None) -> TracebackT def copy_tb(base_tb: TracebackType, tb_next: TracebackType | None) -> TracebackType: # tputil.ProxyOperation is PyPy-only, and there's no way to specify # cpython/pypy in current type checkers. - # Explicit "Any" is not allowed - def controller( # type: ignore[no-any-unimported,misc] + def controller( # type: ignore[no-any-unimported] operation: tputil.ProxyOperation, - ) -> Any | None: + ) -> object | None: # Rationale for pragma: I looked fairly carefully and tried a few # things, and AFAICT it's not actually possible to get any # 'opname' that isn't __getattr__ or __getattribute__. So there's diff --git a/src/trio/_core/_run.py b/src/trio/_core/_run.py index 8dbfd9e95..4063368b0 100644 --- a/src/trio/_core/_run.py +++ b/src/trio/_core/_run.py @@ -71,19 +71,19 @@ # for some strange reason Sphinx works with outcome.Outcome, but not Outcome, in # start_guest_run. Same with types.FrameType in iter_await_frames import outcome - from typing_extensions import Self, TypeVar, TypeVarTuple, Unpack + from typing_extensions import ParamSpec, Self, TypeVar, TypeVarTuple, Unpack PosArgT = TypeVarTuple("PosArgT") StatusT = TypeVar("StatusT", default=None) StatusT_contra = TypeVar("StatusT_contra", contravariant=True, default=None) + PS = ParamSpec("PS") else: from typing import TypeVar StatusT = TypeVar("StatusT") StatusT_contra = TypeVar("StatusT_contra", contravariant=True) + PS = TypeVar("PS") -# Explicit "Any" is not allowed -FnT = TypeVar("FnT", bound="Callable[..., Any]") # type: ignore[misc] RetT = TypeVar("RetT") @@ -103,8 +103,7 @@ class _NoStatus(metaclass=NoPublicConstructor): # Decorator to mark methods public. This does nothing by itself, but # trio/_tools/gen_exports.py looks for it. -# Explicit "Any" is not allowed -def _public(fn: FnT) -> FnT: # type: ignore[misc] +def _public(fn: Callable[PS, RetT]) -> Callable[PS, RetT]: return fn @@ -1290,7 +1289,7 @@ async def start( # type: ignore[misc] async_fn: Callable[..., Awaitable[object]], *args: object, name: object = None, - ) -> Any: + ) -> Any | None: r"""Creates and initializes a child task. Like :meth:`start_soon`, but blocks until the new task has @@ -1341,8 +1340,10 @@ async def async_fn(arg1, arg2, *, task_status=trio.TASK_STATUS_IGNORED): # set strict_exception_groups = True to make sure we always unwrap # *this* nursery's exceptiongroup async with open_nursery(strict_exception_groups=True) as old_nursery: - # Explicit "Any" is not allowed - task_status: _TaskStatus[Any] = _TaskStatus(old_nursery, self) # type: ignore[misc] + task_status: _TaskStatus[object | None] = _TaskStatus( + old_nursery, + self, + ) thunk = functools.partial(async_fn, task_status=task_status) task = GLOBAL_RUN_CONTEXT.runner.spawn_impl( thunk, From 55964ad8687405e9bb31f5057cc5d639233def11 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 28 Oct 2024 00:43:17 -0500 Subject: [PATCH 18/52] Get rid of a bunch more `Any`s and resolve mypy issues --- src/trio/_core/_concat_tb.py | 8 ++- src/trio/_core/_ki.py | 8 ++- src/trio/_core/_run.py | 6 +- src/trio/_core/_tests/test_guest_mode.py | 61 ++++++++++++------ src/trio/_core/_tests/test_ki.py | 5 +- src/trio/_core/_tests/test_parking_lot.py | 12 +++- src/trio/_core/_tests/test_run.py | 12 +++- src/trio/_core/_thread_cache.py | 11 +++- src/trio/_core/_traps.py | 62 ++++++++++++------- src/trio/_file_io.py | 5 +- src/trio/_path.py | 2 +- src/trio/_ssl.py | 18 +++--- .../test_highlevel_open_tcp_listeners.py | 6 +- .../_tests/test_highlevel_serve_listeners.py | 10 ++- src/trio/_tests/test_highlevel_ssl_helpers.py | 27 ++++---- src/trio/_tests/test_subprocess.py | 8 ++- 16 files changed, 172 insertions(+), 89 deletions(-) diff --git a/src/trio/_core/_concat_tb.py b/src/trio/_core/_concat_tb.py index 1334741c0..fbd3186eb 100644 --- a/src/trio/_core/_concat_tb.py +++ b/src/trio/_core/_concat_tb.py @@ -1,7 +1,7 @@ from __future__ import annotations from types import TracebackType -from typing import ClassVar, cast +from typing import TYPE_CHECKING, ClassVar, cast ################################################################ # concat_tb @@ -88,7 +88,7 @@ def copy_tb(base_tb: TracebackType, tb_next: TracebackType | None) -> TracebackT # cpython/pypy in current type checkers. def controller( # type: ignore[no-any-unimported] operation: tputil.ProxyOperation, - ) -> object | None: + ) -> TracebackType | None: # Rationale for pragma: I looked fairly carefully and tried a few # things, and AFAICT it's not actually possible to get any # 'opname' that isn't __getattr__ or __getattribute__. So there's @@ -101,8 +101,10 @@ def controller( # type: ignore[no-any-unimported] "__getattr__", } and operation.args[0] == "tb_next" - ): # pragma: no cover + ) or TYPE_CHECKING: # pragma: no cover return tb_next + if TYPE_CHECKING: + raise RuntimeError("Should not be possible") return operation.delegate() # Delegate is reverting to original behaviour return cast( diff --git a/src/trio/_core/_ki.py b/src/trio/_core/_ki.py index 672501f75..79d784537 100644 --- a/src/trio/_core/_ki.py +++ b/src/trio/_core/_ki.py @@ -85,7 +85,13 @@ class _IdRef(weakref.ref[_T]): __slots__ = ("_hash",) _hash: int - def __new__(cls, ob: _T, callback: Callable[[Self], Any] | None = None, /) -> Self: + # Explicit "Any" is not allowed + def __new__( # type: ignore[misc] + cls, + ob: _T, + callback: Callable[[Self], Any] | None = None, + /, + ) -> Self: self: Self = weakref.ref.__new__(cls, ob, callback) self._hash = object.__hash__(ob) return self diff --git a/src/trio/_core/_run.py b/src/trio/_core/_run.py index 4063368b0..9739ba04c 100644 --- a/src/trio/_core/_run.py +++ b/src/trio/_core/_run.py @@ -71,18 +71,16 @@ # for some strange reason Sphinx works with outcome.Outcome, but not Outcome, in # start_guest_run. Same with types.FrameType in iter_await_frames import outcome - from typing_extensions import ParamSpec, Self, TypeVar, TypeVarTuple, Unpack + from typing_extensions import Self, TypeVar, TypeVarTuple, Unpack PosArgT = TypeVarTuple("PosArgT") StatusT = TypeVar("StatusT", default=None) StatusT_contra = TypeVar("StatusT_contra", contravariant=True, default=None) - PS = ParamSpec("PS") else: from typing import TypeVar StatusT = TypeVar("StatusT") StatusT_contra = TypeVar("StatusT_contra", contravariant=True) - PS = TypeVar("PS") RetT = TypeVar("RetT") @@ -103,7 +101,7 @@ class _NoStatus(metaclass=NoPublicConstructor): # Decorator to mark methods public. This does nothing by itself, but # trio/_tools/gen_exports.py looks for it. -def _public(fn: Callable[PS, RetT]) -> Callable[PS, RetT]: +def _public(fn: RetT) -> RetT: return fn diff --git a/src/trio/_core/_tests/test_guest_mode.py b/src/trio/_core/_tests/test_guest_mode.py index 2284ec01c..2a2bee5ca 100644 --- a/src/trio/_core/_tests/test_guest_mode.py +++ b/src/trio/_core/_tests/test_guest_mode.py @@ -11,12 +11,11 @@ import time import traceback import warnings -from collections.abc import AsyncGenerator, Awaitable, Callable +from collections.abc import AsyncGenerator, Awaitable, Callable, Sequence from functools import partial from math import inf from typing import ( TYPE_CHECKING, - Any, NoReturn, TypeVar, ) @@ -26,7 +25,7 @@ import trio import trio.testing -from trio.abc import Instrument +from trio.abc import Clock, Instrument from ..._util import signal_raise from .tutil import gc_collect_harder, restore_unraisablehook @@ -37,7 +36,7 @@ from trio._channel import MemorySendChannel T = TypeVar("T") -InHost: TypeAlias = Callable[[object], None] +InHost: TypeAlias = Callable[[Callable[[], object]], None] # The simplest possible "host" loop. @@ -46,12 +45,15 @@ # our main # - final result is returned # - any unhandled exceptions cause an immediate crash -# Explicit "Any" is not allowed -def trivial_guest_run( # type: ignore[misc] - trio_fn: Callable[..., Awaitable[T]], +def trivial_guest_run( + trio_fn: Callable[[InHost], Awaitable[T]], *, in_host_after_start: Callable[[], None] | None = None, - **start_guest_run_kwargs: Any, + host_uses_signal_set_wakeup_fd: bool = False, + clock: Clock | None = None, + instruments: Sequence[Instrument] = (), + restrict_keyboard_interrupt_to_checkpoints: bool = False, + strict_exception_groups: bool = True, ) -> T: todo: queue.Queue[tuple[str, Outcome[T] | Callable[[], object]]] = queue.Queue() @@ -87,7 +89,11 @@ def done_callback(outcome: Outcome[T]) -> None: run_sync_soon_threadsafe=run_sync_soon_threadsafe, run_sync_soon_not_threadsafe=run_sync_soon_not_threadsafe, done_callback=done_callback, - **start_guest_run_kwargs, + host_uses_signal_set_wakeup_fd=host_uses_signal_set_wakeup_fd, + clock=clock, + instruments=instruments, + restrict_keyboard_interrupt_to_checkpoints=restrict_keyboard_interrupt_to_checkpoints, + strict_exception_groups=strict_exception_groups, ) if in_host_after_start is not None: in_host_after_start() @@ -171,10 +177,16 @@ async def early_task() -> None: assert res == "ok" assert set(record) == {"system task ran", "main task ran", "run_sync_soon cb ran"} - class BadClock: + class BadClock(Clock): def start_clock(self) -> NoReturn: raise ValueError("whoops") + def current_time(self) -> float: + raise NotImplementedError() + + def deadline_to_sleep_time(self, deadline: float) -> float: + raise NotImplementedError() + def after_start_never_runs() -> None: # pragma: no cover pytest.fail("shouldn't get here") @@ -431,12 +443,16 @@ async def abandoned_main(in_host: InHost) -> None: trio.current_time() -# Explicit "Any" is not allowed -def aiotrio_run( # type: ignore[misc] - trio_fn: Callable[..., Awaitable[T]], +def aiotrio_run( + trio_fn: Callable[[], Awaitable[T]], *, pass_not_threadsafe: bool = True, - **start_guest_run_kwargs: Any, + run_sync_soon_not_threadsafe: InHost | None = None, + host_uses_signal_set_wakeup_fd: bool = False, + clock: Clock | None = None, + instruments: Sequence[Instrument] = (), + restrict_keyboard_interrupt_to_checkpoints: bool = False, + strict_exception_groups: bool = True, ) -> T: loop = asyncio.new_event_loop() @@ -448,13 +464,18 @@ def trio_done_callback(main_outcome: Outcome[object]) -> None: trio_done_fut.set_result(main_outcome) if pass_not_threadsafe: - start_guest_run_kwargs["run_sync_soon_not_threadsafe"] = loop.call_soon + run_sync_soon_not_threadsafe = loop.call_soon trio.lowlevel.start_guest_run( trio_fn, run_sync_soon_threadsafe=loop.call_soon_threadsafe, done_callback=trio_done_callback, - **start_guest_run_kwargs, + run_sync_soon_not_threadsafe=run_sync_soon_not_threadsafe, + host_uses_signal_set_wakeup_fd=host_uses_signal_set_wakeup_fd, + clock=clock, + instruments=instruments, + restrict_keyboard_interrupt_to_checkpoints=restrict_keyboard_interrupt_to_checkpoints, + strict_exception_groups=strict_exception_groups, ) return (await trio_done_fut).unwrap() # type: ignore[no-any-return] @@ -557,12 +578,14 @@ async def crash_in_worker_thread_io(in_host: InHost) -> None: t = threading.current_thread() old_get_events = trio._core._run.TheIOManager.get_events - # Explicit "Any" is not allowed - def bad_get_events(*args: Any) -> object: # type: ignore[misc] + def bad_get_events( + self: trio._core._run.TheIOManager, + timeout: float, + ) -> trio._core._run.EventResult: if threading.current_thread() is not t: raise ValueError("oh no!") else: - return old_get_events(*args) + return old_get_events(self, timeout) m.setattr("trio._core._run.TheIOManager.get_events", bad_get_events) diff --git a/src/trio/_core/_tests/test_ki.py b/src/trio/_core/_tests/test_ki.py index d403cfa7a..c25a54f19 100644 --- a/src/trio/_core/_tests/test_ki.py +++ b/src/trio/_core/_tests/test_ki.py @@ -678,7 +678,10 @@ async def _consume_async_generator(agen: AsyncGenerator[None, None]) -> None: await agen.aclose() -def _consume_function_for_coverage(fn: Callable[..., object]) -> None: +# Explicit "Any" is not allowed +def _consume_function_for_coverage( # type: ignore[misc] + fn: Callable[..., object], +) -> None: result = fn() if inspect.isasyncgen(result): result = _consume_async_generator(result) diff --git a/src/trio/_core/_tests/test_parking_lot.py b/src/trio/_core/_tests/test_parking_lot.py index d9afee83d..809fb2824 100644 --- a/src/trio/_core/_tests/test_parking_lot.py +++ b/src/trio/_core/_tests/test_parking_lot.py @@ -304,9 +304,10 @@ async def test_parking_lot_breaker_registration() -> None: # registering a task as breaker on an already broken lot is fine lot.break_lot() - child_task = None + child_task: _core.Task | None = None async with trio.open_nursery() as nursery: child_task = await nursery.start(dummy_task) + assert isinstance(child_task, _core.Task) add_parking_lot_breaker(child_task, lot) nursery.cancel_scope.cancel() assert lot.broken_by == [task, child_task] @@ -339,6 +340,9 @@ async def test_parking_lot_multiple_breakers_exit() -> None: child_task1 = await nursery.start(dummy_task) child_task2 = await nursery.start(dummy_task) child_task3 = await nursery.start(dummy_task) + assert isinstance(child_task1, _core.Task) + assert isinstance(child_task2, _core.Task) + assert isinstance(child_task3, _core.Task) add_parking_lot_breaker(child_task1, lot) add_parking_lot_breaker(child_task2, lot) add_parking_lot_breaker(child_task3, lot) @@ -350,9 +354,11 @@ async def test_parking_lot_multiple_breakers_exit() -> None: async def test_parking_lot_breaker_register_exited_task() -> None: lot = ParkingLot() - child_task = None + child_task: _core.Task | None = None async with trio.open_nursery() as nursery: - child_task = await nursery.start(dummy_task) + value = await nursery.start(dummy_task) + assert isinstance(value, _core.Task) + child_task = value nursery.cancel_scope.cancel() # trying to register an exited task as lot breaker errors with pytest.raises( diff --git a/src/trio/_core/_tests/test_run.py b/src/trio/_core/_tests/test_run.py index 85691402b..999f0755e 100644 --- a/src/trio/_core/_tests/test_run.py +++ b/src/trio/_core/_tests/test_run.py @@ -823,7 +823,9 @@ async def task3(task_status: _core.TaskStatus[_core.CancelScope]) -> None: await sleep_forever() async with _core.open_nursery() as nursery: - scope: _core.CancelScope = await nursery.start(task3) + value = await nursery.start(task3) + assert isinstance(value, _core.CancelScope) + scope: _core.CancelScope = value with pytest.raises(RuntimeError, match="from unrelated"): scope.__exit__(None, None, None) scope.cancel() @@ -1963,7 +1965,9 @@ async def sleeping_children( # Cancelling the setup_nursery just *before* calling started() async with _core.open_nursery() as nursery: - target_nursery: _core.Nursery = await nursery.start(setup_nursery) + value = await nursery.start(setup_nursery) + assert isinstance(value, _core.Nursery) + target_nursery: _core.Nursery = value await target_nursery.start( sleeping_children, target_nursery.cancel_scope.cancel, @@ -1971,7 +1975,9 @@ async def sleeping_children( # Cancelling the setup_nursery just *after* calling started() async with _core.open_nursery() as nursery: - target_nursery = await nursery.start(setup_nursery) + value = await nursery.start(setup_nursery) + assert isinstance(value, _core.Nursery) + target_nursery = value await target_nursery.start(sleeping_children, lambda: None) target_nursery.cancel_scope.cancel() diff --git a/src/trio/_core/_thread_cache.py b/src/trio/_core/_thread_cache.py index 9dffe898e..189d5a583 100644 --- a/src/trio/_core/_thread_cache.py +++ b/src/trio/_core/_thread_cache.py @@ -7,10 +7,13 @@ from functools import partial from itertools import count from threading import Lock, Thread -from typing import Any, Callable, Generic, TypeVar +from typing import TYPE_CHECKING, Any, Generic, TypeVar import outcome +if TYPE_CHECKING: + from collections.abc import Callable + RetT = TypeVar("RetT") @@ -126,6 +129,8 @@ def darwin_namefunc( class WorkerThread(Generic[RetT]): + __slots__ = ("_default_name", "_job", "_thread", "_thread_cache", "_worker_lock") + def __init__(self, thread_cache: ThreadCache) -> None: self._job: ( tuple[ @@ -207,8 +212,10 @@ def _work(self) -> None: class ThreadCache: + __slots__ = ("_idle_workers",) + def __init__(self) -> None: - # Explicit "Any" is not allowed + # Explicit "Any" not allowed self._idle_workers: dict[WorkerThread[Any], None] = {} # type: ignore[misc] def start_thread_soon( diff --git a/src/trio/_core/_traps.py b/src/trio/_core/_traps.py index 29146b6b4..33ee03ea2 100644 --- a/src/trio/_core/_traps.py +++ b/src/trio/_core/_traps.py @@ -4,7 +4,8 @@ import enum import types -from typing import TYPE_CHECKING, Any, Callable, NoReturn +from collections.abc import Awaitable, Callable +from typing import TYPE_CHECKING, Any, NoReturn, Union, cast import attrs import outcome @@ -12,10 +13,40 @@ from . import _run if TYPE_CHECKING: + from collections.abc import Generator + from typing_extensions import TypeAlias from ._run import Task +RaiseCancelT: TypeAlias = Callable[[], NoReturn] + + +# This class object is used as a singleton. +# Not exported in the trio._core namespace, but imported directly by _run. +class CancelShieldedCheckpoint: + __slots__ = () + + +# Not exported in the trio._core namespace, but imported directly by _run. +@attrs.frozen(slots=False) +class WaitTaskRescheduled: + abort_func: Callable[[RaiseCancelT], Abort] + + +# Not exported in the trio._core namespace, but imported directly by _run. +@attrs.frozen(slots=False) +class PermanentlyDetachCoroutineObject: + final_outcome: outcome.Outcome[object] + + +MessageType: TypeAlias = Union[ + type[CancelShieldedCheckpoint], + WaitTaskRescheduled, + PermanentlyDetachCoroutineObject, + object, +] + # Helper for the bottommost 'yield'. You can't use 'yield' inside an async # function, but you can inside a generator, and if you decorate your generator @@ -25,14 +56,18 @@ # tracking machinery. Since our traps are public APIs, we make them real async # functions, and then this helper takes care of the actual yield: @types.coroutine -def _async_yield(obj: Any) -> Any: # type: ignore[misc] +def _real_async_yield( + obj: MessageType, +) -> Generator[MessageType, None, None]: return (yield obj) -# This class object is used as a singleton. -# Not exported in the trio._core namespace, but imported directly by _run. -class CancelShieldedCheckpoint: - pass +# Real yield value is from trio's main loop, but type checkers can't +# understand that, so we cast it to make type checkers understand. +_async_yield = cast( + Callable[[MessageType], Awaitable[outcome.Outcome[object]]], + _real_async_yield, +) async def cancel_shielded_checkpoint() -> None: @@ -66,15 +101,6 @@ class Abort(enum.Enum): FAILED = 2 -# Not exported in the trio._core namespace, but imported directly by _run. -@attrs.frozen(slots=False) -class WaitTaskRescheduled: - abort_func: Callable[[RaiseCancelT], Abort] - - -RaiseCancelT: TypeAlias = Callable[[], NoReturn] - - # Should always return the type a Task "expects", unless you willfully reschedule it # with a bad value. # Explicit "Any" is not allowed @@ -182,12 +208,6 @@ def abort(inner_raise_cancel): return (await _async_yield(WaitTaskRescheduled(abort_func))).unwrap() -# Not exported in the trio._core namespace, but imported directly by _run. -@attrs.frozen(slots=False) -class PermanentlyDetachCoroutineObject: - final_outcome: outcome.Outcome[object] - - # Explicit "Any" is not allowed async def permanently_detach_coroutine_object( # type: ignore[misc] final_outcome: outcome.Outcome[object], diff --git a/src/trio/_file_io.py b/src/trio/_file_io.py index 50478af62..677c1b036 100644 --- a/src/trio/_file_io.py +++ b/src/trio/_file_io.py @@ -435,8 +435,7 @@ async def open_file( # type: ignore[misc] # Any usage matches builtins.open(). ) -> AsyncIOWrapper[IO[Any]]: ... -# Explicit "Any" is not allowed -async def open_file( # type: ignore[misc] +async def open_file( file: _OpenFile, mode: str = "r", buffering: int = -1, @@ -445,7 +444,7 @@ async def open_file( # type: ignore[misc] newline: str | None = None, closefd: bool = True, opener: _Opener | None = None, -) -> AsyncIOWrapper[Any]: +) -> AsyncIOWrapper[object]: """Asynchronous version of :func:`open`. Returns: diff --git a/src/trio/_path.py b/src/trio/_path.py index 4e52fec24..2e42328f6 100644 --- a/src/trio/_path.py +++ b/src/trio/_path.py @@ -32,7 +32,7 @@ # Explicit "Any" is not allowed def _wraps_async( # type: ignore[misc] - wrapped: Callable[..., Any], + wrapped: Callable[..., object], ) -> Callable[[Callable[P, T]], Callable[P, Awaitable[T]]]: def decorator(fn: Callable[P, T]) -> Callable[P, Awaitable[T]]: async def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: diff --git a/src/trio/_ssl.py b/src/trio/_ssl.py index 46ab0776e..48eac8c27 100644 --- a/src/trio/_ssl.py +++ b/src/trio/_ssl.py @@ -16,6 +16,10 @@ if TYPE_CHECKING: from collections.abc import Awaitable, Callable + from typing_extensions import TypeVarTuple, Unpack + + Ts = TypeVarTuple("Ts") + # General theory of operation: # # We implement an API that closely mirrors the stdlib ssl module's blocking @@ -219,10 +223,11 @@ class NeedHandshakeError(Exception): class _Once: - # Explicit "Any" is not allowed - def __init__( # type: ignore[misc] + __slots__ = ("_afn", "_args", "_done", "started") + + def __init__( self, - afn: Callable[..., Awaitable[object]], + afn: Callable[[], Awaitable[object]], *args: object, ) -> None: self._afn = afn @@ -454,11 +459,10 @@ def _check_status(self) -> None: # comments, though, just make sure to think carefully if you ever have to # touch it. The big comment at the top of this file will help explain # too. - # Explicit "Any" is not allowed - async def _retry( # type: ignore[misc] + async def _retry( self, - fn: Callable[..., T], - *args: object, + fn: Callable[[*Ts], T], + *args: Unpack[Ts], ignore_want_read: bool = False, is_handshake: bool = False, ) -> T | None: diff --git a/src/trio/_tests/test_highlevel_open_tcp_listeners.py b/src/trio/_tests/test_highlevel_open_tcp_listeners.py index 734427a53..6af372185 100644 --- a/src/trio/_tests/test_highlevel_open_tcp_listeners.py +++ b/src/trio/_tests/test_highlevel_open_tcp_listeners.py @@ -4,7 +4,7 @@ import socket as stdlib_socket import sys from socket import AddressFamily, SocketKind -from typing import TYPE_CHECKING, overload +from typing import TYPE_CHECKING, cast, overload import attrs import pytest @@ -315,7 +315,9 @@ async def handler(stream: SendStream) -> None: async with trio.open_nursery() as nursery: # nursery.start is incorrectly typed, awaiting #2773 - listeners: list[SocketListener] = await nursery.start(serve_tcp, handler, 0) + value = await nursery.start(serve_tcp, handler, 0) + assert isinstance(value, list) + listeners = cast(list[SocketListener], value) stream = await open_stream_to_socket_listener(listeners[0]) async with stream: assert await stream.receive_some(1) == b"x" diff --git a/src/trio/_tests/test_highlevel_serve_listeners.py b/src/trio/_tests/test_highlevel_serve_listeners.py index 0ce82e784..013d13078 100644 --- a/src/trio/_tests/test_highlevel_serve_listeners.py +++ b/src/trio/_tests/test_highlevel_serve_listeners.py @@ -2,7 +2,7 @@ import errno from functools import partial -from typing import TYPE_CHECKING, NoReturn +from typing import TYPE_CHECKING, NoReturn, cast import attrs @@ -96,11 +96,13 @@ async def do_tests(parent_nursery: Nursery) -> None: parent_nursery.cancel_scope.cancel() async with trio.open_nursery() as nursery: - l2: list[MemoryListener] = await nursery.start( + value = await nursery.start( trio.serve_listeners, handler, listeners, ) + assert isinstance(value, list) + l2 = cast(list[MemoryListener], value) assert l2 == listeners # This is just split into another function because gh-136 isn't # implemented yet @@ -172,7 +174,9 @@ async def connection_watcher( # the exception is wrapped twice because we open two nested nurseries with RaisesGroup(RaisesGroup(Done)): async with trio.open_nursery() as nursery: - handler_nursery: trio.Nursery = await nursery.start(connection_watcher) + value = await nursery.start(connection_watcher) + assert isinstance(value, trio.Nursery) + handler_nursery: trio.Nursery = value await nursery.start( partial( trio.serve_listeners, diff --git a/src/trio/_tests/test_highlevel_ssl_helpers.py b/src/trio/_tests/test_highlevel_ssl_helpers.py index 340264a2c..4dc904910 100644 --- a/src/trio/_tests/test_highlevel_ssl_helpers.py +++ b/src/trio/_tests/test_highlevel_ssl_helpers.py @@ -1,7 +1,7 @@ from __future__ import annotations from functools import partial -from typing import TYPE_CHECKING, Any, NoReturn +from typing import TYPE_CHECKING, Any, NoReturn, cast import attrs import pytest @@ -10,11 +10,13 @@ import trio.testing from trio.socket import AF_INET, IPPROTO_TCP, SOCK_STREAM +from .._highlevel_socket import SocketListener from .._highlevel_ssl_helpers import ( open_ssl_over_tcp_listeners, open_ssl_over_tcp_stream, serve_ssl_over_tcp, ) +from .._ssl import SSLListener # using noqa because linters don't understand how pytest fixtures work. from .test_ssl import SERVER_CTX, client_ctx # noqa: F401 @@ -25,9 +27,6 @@ from trio.abc import Stream - from .._highlevel_socket import SocketListener - from .._ssl import SSLListener - async def echo_handler(stream: Stream) -> None: async with stream: @@ -83,17 +82,17 @@ async def test_open_ssl_over_tcp_stream_and_everything_else( # TODO: this function wraps an SSLListener around a SocketListener, this is illegal # according to current type hints, and probably for good reason. But there should # maybe be a different wrapper class/function that could be used instead? - res: list[SSLListener[SocketListener]] = ( # type: ignore[type-var] - await nursery.start( - partial( - serve_ssl_over_tcp, - echo_handler, - 0, - SERVER_CTX, - host="127.0.0.1", - ), - ) + value = await nursery.start( + partial( + serve_ssl_over_tcp, + echo_handler, + 0, + SERVER_CTX, + host="127.0.0.1", + ), ) + assert isinstance(value, list) + res = cast(list[SSLListener[SocketListener]], value) # type: ignore[type-var] (listener,) = res async with listener: # listener.transport_listener is of type Listener[Stream] diff --git a/src/trio/_tests/test_subprocess.py b/src/trio/_tests/test_subprocess.py index 8c8d0faba..e2c6febd1 100644 --- a/src/trio/_tests/test_subprocess.py +++ b/src/trio/_tests/test_subprocess.py @@ -102,7 +102,9 @@ async def open_process_then_kill(*args: Any, **kwargs: Any) -> AsyncIterator[Pro async def run_process_in_nursery(*args: Any, **kwargs: Any) -> AsyncIterator[Process]: async with _core.open_nursery() as nursery: kwargs.setdefault("check", False) - proc: Process = await nursery.start(partial(run_process, *args, **kwargs)) + value = await nursery.start(partial(run_process, *args, **kwargs)) + assert isinstance(value, Process) + proc: Process = value yield proc nursery.cancel_scope.cancel() @@ -634,7 +636,9 @@ async def test_warn_on_cancel_SIGKILL_escalation( async def test_run_process_background_fail() -> None: with RaisesGroup(subprocess.CalledProcessError): async with _core.open_nursery() as nursery: - proc: Process = await nursery.start(run_process, EXIT_FALSE) + value = await nursery.start(run_process, EXIT_FALSE) + assert isinstance(value, Process) + proc: Process = value assert proc.returncode == 1 From e888514841aae9a1243b8655fe7eb25e0ffd5a2b Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 28 Oct 2024 00:49:02 -0500 Subject: [PATCH 19/52] Match other TypeVarTuple usage --- src/trio/_ssl.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/trio/_ssl.py b/src/trio/_ssl.py index 48eac8c27..0a0419fbc 100644 --- a/src/trio/_ssl.py +++ b/src/trio/_ssl.py @@ -227,8 +227,8 @@ class _Once: def __init__( self, - afn: Callable[[], Awaitable[object]], - *args: object, + afn: Callable[[*Ts], Awaitable[object]], + *args: Unpack[Ts], ) -> None: self._afn = afn self._args = args From 30db0d8022c685bb3cfddd4c47619e6076f57f4f Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 28 Oct 2024 00:54:01 -0500 Subject: [PATCH 20/52] Mark variable as nonlocal --- src/trio/_core/_tests/test_guest_mode.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/trio/_core/_tests/test_guest_mode.py b/src/trio/_core/_tests/test_guest_mode.py index 2a2bee5ca..2dc33e0f5 100644 --- a/src/trio/_core/_tests/test_guest_mode.py +++ b/src/trio/_core/_tests/test_guest_mode.py @@ -457,6 +457,7 @@ def aiotrio_run( loop = asyncio.new_event_loop() async def aio_main() -> T: + nonlocal run_sync_soon_not_threadsafe trio_done_fut = loop.create_future() def trio_done_callback(main_outcome: Outcome[object]) -> None: From 7707361928310e9a454b2dd3705fae4c3c3e2ccd Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 28 Oct 2024 01:09:17 -0500 Subject: [PATCH 21/52] Cast asyncio run in loop to be InHost --- src/trio/_core/_tests/test_guest_mode.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/trio/_core/_tests/test_guest_mode.py b/src/trio/_core/_tests/test_guest_mode.py index 2dc33e0f5..678874fec 100644 --- a/src/trio/_core/_tests/test_guest_mode.py +++ b/src/trio/_core/_tests/test_guest_mode.py @@ -18,6 +18,7 @@ TYPE_CHECKING, NoReturn, TypeVar, + cast, ) import pytest @@ -465,7 +466,7 @@ def trio_done_callback(main_outcome: Outcome[object]) -> None: trio_done_fut.set_result(main_outcome) if pass_not_threadsafe: - run_sync_soon_not_threadsafe = loop.call_soon + run_sync_soon_not_threadsafe = cast(InHost, loop.call_soon) trio.lowlevel.start_guest_run( trio_fn, From e99b69f9d389fa9f68d196a7bf599b396143708a Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 28 Oct 2024 01:25:21 -0500 Subject: [PATCH 22/52] Handle case where `names` does not exist in node for some reason --- src/trio/_tests/test_exports.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index d82481402..de2449755 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -390,11 +390,13 @@ def lookup_symbol(symbol: str) -> dict[str, str]: assert "node" in cached_type_info node = cached_type_info["node"] - static_names = no_hidden(k for k in node["names"] if not k.startswith(".")) + static_names = no_hidden( + k for k in node.get("names", ()) if not k.startswith(".") + ) for symbol in node["mro"][1:]: node = lookup_symbol(symbol)["node"] static_names |= no_hidden( - k for k in node["names"] if not k.startswith(".") + k for k in node.get("names", ()) if not k.startswith(".") ) static_names -= ignore_names From aee4a770ddebb3d631a07e81399a2d1fd8982ece Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 28 Oct 2024 01:30:28 -0500 Subject: [PATCH 23/52] Hopefully fix jedi issue --- src/trio/_core/_traps.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/trio/_core/_traps.py b/src/trio/_core/_traps.py index 33ee03ea2..85135c31c 100644 --- a/src/trio/_core/_traps.py +++ b/src/trio/_core/_traps.py @@ -4,8 +4,10 @@ import enum import types -from collections.abc import Awaitable, Callable -from typing import TYPE_CHECKING, Any, NoReturn, Union, cast +from collections.abc import Awaitable + +# Jedi gets mad in test_static_tool_sees_class_members if we use collections Callable +from typing import TYPE_CHECKING, Any, Callable, NoReturn, Union, cast import attrs import outcome From e157589eff6ed63992c079e51df40f32dc6b0155 Mon Sep 17 00:00:00 2001 From: EXPLOSION Date: Mon, 28 Oct 2024 03:47:44 -0400 Subject: [PATCH 24/52] Check the hashes are the same --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 10965e132..f44581d1e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,6 +51,7 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - run: sha256sum ./test-requirements.txt - name: Setup python uses: actions/setup-python@v5 with: From 62f89faaa9153548e126c841668dad0e62260bf2 Mon Sep 17 00:00:00 2001 From: EXPLOSION Date: Mon, 28 Oct 2024 03:52:50 -0400 Subject: [PATCH 25/52] Get the hash glob makes --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f44581d1e..1e10155c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,6 +52,12 @@ jobs: - name: Checkout uses: actions/checkout@v4 - run: sha256sum ./test-requirements.txt + - uses: actions/github-script@v7 + with: + script: | + console.log(glob.hashFiles(["test-requirements.txt"])) + console.log(glob.hashFiles(["./test-requirements.txt"])) + console.log(glob.hashFiles(["**/requirements.txt"])) // default - name: Setup python uses: actions/setup-python@v5 with: From ca48ef6755179aa8b7365a0fd572cb56de20d73e Mon Sep 17 00:00:00 2001 From: EXPLOSION Date: Mon, 28 Oct 2024 03:58:19 -0400 Subject: [PATCH 26/52] Fix inputs to glob.hashFiles --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1e10155c9..86f742db3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,9 +55,9 @@ jobs: - uses: actions/github-script@v7 with: script: | - console.log(glob.hashFiles(["test-requirements.txt"])) - console.log(glob.hashFiles(["./test-requirements.txt"])) - console.log(glob.hashFiles(["**/requirements.txt"])) // default + console.log(await glob.hashFiles("test-requirements.txt")) + console.log(await glob.hashFiles("./test-requirements.txt")) + console.log(await glob.hashFiles("**/requirements.txt")) // default - name: Setup python uses: actions/setup-python@v5 with: From 28b4abc42c187081fda7ba331dfb265edf1c709e Mon Sep 17 00:00:00 2001 From: EXPLOSION Date: Mon, 28 Oct 2024 04:04:36 -0400 Subject: [PATCH 27/52] Remove testing hashes --- .github/workflows/ci.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86f742db3..10965e132 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,13 +51,6 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - run: sha256sum ./test-requirements.txt - - uses: actions/github-script@v7 - with: - script: | - console.log(await glob.hashFiles("test-requirements.txt")) - console.log(await glob.hashFiles("./test-requirements.txt")) - console.log(await glob.hashFiles("**/requirements.txt")) // default - name: Setup python uses: actions/setup-python@v5 with: From 321977cc081d64b67bb3dc3ffd3cd9cd525a84c7 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 28 Oct 2024 09:05:41 -0500 Subject: [PATCH 28/52] Enable pre-commit.ci pull-request autofixing (#3123) --- .pre-commit-config.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 844adc508..6d37c6c39 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,5 @@ ci: - autofix_commit_msg: "[pre-commit.ci] auto fixes from pre-commit.com hooks" - autofix_prs: false - autoupdate_commit_msg: "[pre-commit.ci] pre-commit autoupdate" + autofix_prs: true autoupdate_schedule: weekly submodules: false skip: [regenerate-files] From a1e4916a532416f7d82337de4484d86da9b15bd6 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:06:14 -0500 Subject: [PATCH 29/52] Apply requested changes from code review Co-authored-by: John Litborn <11260241+jakkdl@users.noreply.github.com> --- src/trio/_core/_io_windows.py | 23 +++++++++++---- src/trio/_core/_run.py | 1 - src/trio/_core/_tests/test_run.py | 48 +++++++++---------------------- src/trio/_core/_traps.py | 5 ++-- src/trio/_socket.py | 3 +- 5 files changed, 33 insertions(+), 47 deletions(-) diff --git a/src/trio/_core/_io_windows.py b/src/trio/_core/_io_windows.py index 7effe76b0..960f24582 100644 --- a/src/trio/_core/_io_windows.py +++ b/src/trio/_core/_io_windows.py @@ -7,8 +7,8 @@ from contextlib import contextmanager from typing import ( TYPE_CHECKING, - Any, Literal, + Protocol, TypeVar, cast, ) @@ -249,14 +249,26 @@ class AFDWaiters: current_op: AFDPollOp | None = None +class AFDHandle(Protocol): + Handle: Handle + Status: int + Events: int + + +class AFDPollInfo(Protocol): + Timeout: int + NumberOfHandles: int + Exclusive: int + Handles: list[AFDHandle] + + # We also need to bundle up all the info for a single op into a standalone # object, because we need to keep all these objects alive until the operation # finishes, even if we're throwing it away. @attrs.frozen(eq=False) -# Explicit "Any" is not allowed -class AFDPollOp: # type: ignore[misc] +class AFDPollOp: lpOverlapped: CData - poll_info: Any # type: ignore[misc] + poll_info: AFDPollInfo waiters: AFDWaiters afd_group: AFDGroup @@ -685,8 +697,7 @@ def _refresh_afd(self, base_handle: Handle) -> None: lpOverlapped = ffi.new("LPOVERLAPPED") - # Explicit "Any" is not allowed - poll_info: Any = ffi.new("AFD_POLL_INFO *") # type: ignore[misc] + poll_info: AFDPollInfo = ffi.new("AFD_POLL_INFO *") poll_info.Timeout = 2**63 - 1 # INT64_MAX poll_info.NumberOfHandles = 1 poll_info.Exclusive = 0 diff --git a/src/trio/_core/_run.py b/src/trio/_core/_run.py index 9739ba04c..308333a49 100644 --- a/src/trio/_core/_run.py +++ b/src/trio/_core/_run.py @@ -1475,7 +1475,6 @@ def print_stack_for_task(task): """ # Ignore static typing as we're doing lots of dynamic introspection - # Explicit "Any" is not allowed coro: Any = self.coro # type: ignore[misc] while coro is not None: if hasattr(coro, "cr_frame"): diff --git a/src/trio/_core/_tests/test_run.py b/src/trio/_core/_tests/test_run.py index 999f0755e..aafcf9208 100644 --- a/src/trio/_core/_tests/test_run.py +++ b/src/trio/_core/_tests/test_run.py @@ -10,7 +10,7 @@ import weakref from contextlib import ExitStack, contextmanager, suppress from math import inf, nan -from typing import TYPE_CHECKING, Any, NoReturn, TypeVar, cast +from typing import TYPE_CHECKING, NoReturn, TypeVar import outcome import pytest @@ -2295,7 +2295,8 @@ async def detachable_coroutine( await sleep(0) nonlocal task, pdco_outcome task = _core.current_task() - pdco_outcome = await outcome.acapture( + # `No overload variant of "acapture" matches argument types "Callable[[Outcome[object]], Coroutine[Any, Any, object]]", "Outcome[None]"` + pdco_outcome = await outcome.acapture( # type: ignore[call-overload] _core.permanently_detach_coroutine_object, task_outcome, ) @@ -2308,18 +2309,11 @@ async def detachable_coroutine( # is still iterable. At that point anything can be sent into the coroutine, so the .coro type # is wrong. assert pdco_outcome is None - # Explicit "Any" is not allowed - assert ( - not_none(task).coro.send( - cast(Any, "be free!"), # type: ignore[misc] - ) - == "I'm free!" - ) + # `Argument 1 to "send" of "Coroutine" has incompatible type "str"; expected "Outcome[object]"` + assert not_none(task).coro.send("be free!") == "I'm free!" # type: ignore[arg-type] assert pdco_outcome == outcome.Value("be free!") with pytest.raises(StopIteration): - not_none(task).coro.send( - cast(Any, None), # type: ignore[misc] - ) + not_none(task).coro.send(None) # type: ignore[arg-type] # Check the exception paths too task = None @@ -2332,7 +2326,7 @@ async def detachable_coroutine( assert not_none(task).coro.throw(throw_in) == "uh oh" assert pdco_outcome == outcome.Error(throw_in) with pytest.raises(StopIteration): - task.coro.send(cast(Any, None)) + task.coro.send(None) async def bad_detach() -> None: async with _core.open_nursery(): @@ -2384,25 +2378,10 @@ def abort_fn(_: _core.RaiseCancelT) -> _core.Abort: # pragma: no cover await wait_all_tasks_blocked() # Okay, it's detached. Here's our coroutine runner: - # Explicit "Any" is not allowed - assert ( - not_none(task).coro.send( - cast(Any, "not trio!"), # type: ignore[misc] - ) - == 1 - ) - assert ( - not_none(task).coro.send( - cast(Any, None), # type: ignore[misc] - ) - == 2 - ) - assert ( - not_none(task).coro.send( - cast(Any, None), # type: ignore[misc] - ) - == "byebye" - ) + # `Argument 1 to "send" of "Coroutine" has incompatible type "str"; expected "Outcome[object]"` + assert not_none(task).coro.send("not trio!") == 1 # type: ignore[arg-type] + assert not_none(task).coro.send(None) == 2 # type: ignore[arg-type] + assert not_none(task).coro.send(None) == "byebye" # type: ignore[arg-type] # Now it's been reattached, and we can leave the nursery @@ -2432,9 +2411,8 @@ def abort_fn(_: _core.RaiseCancelT) -> _core.Abort: await wait_all_tasks_blocked() assert task is not None nursery.cancel_scope.cancel() - task.coro.send( - cast(Any, None), # type: ignore[misc] - ) + # `Argument 1 to "send" of "Coroutine" has incompatible type "None"; expected "Outcome[object]"` + task.coro.send(None) # type: ignore[arg-type] assert abort_fn_called diff --git a/src/trio/_core/_traps.py b/src/trio/_core/_traps.py index 85135c31c..bef77b768 100644 --- a/src/trio/_core/_traps.py +++ b/src/trio/_core/_traps.py @@ -210,10 +210,9 @@ def abort(inner_raise_cancel): return (await _async_yield(WaitTaskRescheduled(abort_func))).unwrap() -# Explicit "Any" is not allowed -async def permanently_detach_coroutine_object( # type: ignore[misc] +async def permanently_detach_coroutine_object( final_outcome: outcome.Outcome[object], -) -> Any: +) -> object: """Permanently detach the current task from the Trio scheduler. Normally, a Trio task doesn't exit until its coroutine object exits. When diff --git a/src/trio/_socket.py b/src/trio/_socket.py index d40309cd3..0929874e9 100644 --- a/src/trio/_socket.py +++ b/src/trio/_socket.py @@ -750,8 +750,7 @@ async def sendto( __address: tuple[object, ...] | str | Buffer, ) -> int: ... - # Explicit "Any" is not allowed - async def sendto(self, *args: Any) -> int: # type: ignore[misc] + async def sendto(self, *args: object) -> int: raise NotImplementedError if sys.platform != "win32" or ( From c3c0a28ebe6b48456bf9d962c68e50558589e488 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:10:55 -0500 Subject: [PATCH 30/52] Code review suggestions Co-authored-by: John Litborn <11260241+jakkdl@users.noreply.github.com> --- newsfragments/3121.misc.rst | 1 + src/trio/_core/_concat_tb.py | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 newsfragments/3121.misc.rst diff --git a/newsfragments/3121.misc.rst b/newsfragments/3121.misc.rst new file mode 100644 index 000000000..731232877 --- /dev/null +++ b/newsfragments/3121.misc.rst @@ -0,0 +1 @@ +Improve type annotations in several places by removing `Any` usage. diff --git a/src/trio/_core/_concat_tb.py b/src/trio/_core/_concat_tb.py index fbd3186eb..82e525137 100644 --- a/src/trio/_core/_concat_tb.py +++ b/src/trio/_core/_concat_tb.py @@ -103,9 +103,8 @@ def controller( # type: ignore[no-any-unimported] and operation.args[0] == "tb_next" ) or TYPE_CHECKING: # pragma: no cover return tb_next - if TYPE_CHECKING: - raise RuntimeError("Should not be possible") - return operation.delegate() # Delegate is reverting to original behaviour + # Delegate is reverting to original behaviour + return operation.delegate() # type: ignore[no-any-return] return cast( TracebackType, From 63353f406145f509b7621a9f6adcde2119abecb9 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:40:52 -0500 Subject: [PATCH 31/52] Fix type issue --- src/trio/_core/_io_windows.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/trio/_core/_io_windows.py b/src/trio/_core/_io_windows.py index 960f24582..39df2849b 100644 --- a/src/trio/_core/_io_windows.py +++ b/src/trio/_core/_io_windows.py @@ -697,13 +697,14 @@ def _refresh_afd(self, base_handle: Handle) -> None: lpOverlapped = ffi.new("LPOVERLAPPED") - poll_info: AFDPollInfo = ffi.new("AFD_POLL_INFO *") - poll_info.Timeout = 2**63 - 1 # INT64_MAX - poll_info.NumberOfHandles = 1 - poll_info.Exclusive = 0 - poll_info.Handles[0].Handle = base_handle - poll_info.Handles[0].Status = 0 - poll_info.Handles[0].Events = flags + poll_info = ffi.new("AFD_POLL_INFO *") + poll_info_proto = cast(AFDPollInfo, poll_info) + poll_info_proto.Timeout = 2**63 - 1 # INT64_MAX + poll_info_proto.NumberOfHandles = 1 + poll_info_proto.Exclusive = 0 + poll_info_proto.Handles[0].Handle = base_handle + poll_info_proto.Handles[0].Status = 0 + poll_info_proto.Handles[0].Events = flags try: _check( @@ -728,7 +729,9 @@ def _refresh_afd(self, base_handle: Handle) -> None: # Do this last, because it could raise. wake_all(waiters, exc) return - op = AFDPollOp(lpOverlapped, poll_info, waiters, afd_group) + # get rid of duplicate reference, will use poll_info_proto moving on + del poll_info + op = AFDPollOp(lpOverlapped, poll_info_proto, waiters, afd_group) waiters.current_op = op self._afd_ops[lpOverlapped] = op afd_group.size += 1 From 69e60a585d3428235e9be1876cd23a2ba08cefcd Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:48:59 -0500 Subject: [PATCH 32/52] Fix cffi type issues again --- src/trio/_core/_io_windows.py | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/trio/_core/_io_windows.py b/src/trio/_core/_io_windows.py index 39df2849b..6053ff5a9 100644 --- a/src/trio/_core/_io_windows.py +++ b/src/trio/_core/_io_windows.py @@ -697,23 +697,22 @@ def _refresh_afd(self, base_handle: Handle) -> None: lpOverlapped = ffi.new("LPOVERLAPPED") - poll_info = ffi.new("AFD_POLL_INFO *") - poll_info_proto = cast(AFDPollInfo, poll_info) - poll_info_proto.Timeout = 2**63 - 1 # INT64_MAX - poll_info_proto.NumberOfHandles = 1 - poll_info_proto.Exclusive = 0 - poll_info_proto.Handles[0].Handle = base_handle - poll_info_proto.Handles[0].Status = 0 - poll_info_proto.Handles[0].Events = flags + poll_info = cast(AFDPollInfo, ffi.new("AFD_POLL_INFO *")) + poll_info.Timeout = 2**63 - 1 # INT64_MAX + poll_info.NumberOfHandles = 1 + poll_info.Exclusive = 0 + poll_info.Handles[0].Handle = base_handle + poll_info.Handles[0].Status = 0 + poll_info.Handles[0].Events = flags try: _check( kernel32.DeviceIoControl( afd_group.handle, IoControlCodes.IOCTL_AFD_POLL, - poll_info, + cast(ffi.CData, poll_info), ffi.sizeof("AFD_POLL_INFO"), - poll_info, + cast(ffi.CData, poll_info), ffi.sizeof("AFD_POLL_INFO"), ffi.NULL, lpOverlapped, @@ -729,9 +728,7 @@ def _refresh_afd(self, base_handle: Handle) -> None: # Do this last, because it could raise. wake_all(waiters, exc) return - # get rid of duplicate reference, will use poll_info_proto moving on - del poll_info - op = AFDPollOp(lpOverlapped, poll_info_proto, waiters, afd_group) + op = AFDPollOp(lpOverlapped, poll_info, waiters, afd_group) waiters.current_op = op self._afd_ops[lpOverlapped] = op afd_group.size += 1 From 2bc0da37b11896b270ce16ec0abb28e9341a14be Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:56:01 -0500 Subject: [PATCH 33/52] Use correct `CData` --- src/trio/_core/_io_windows.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/trio/_core/_io_windows.py b/src/trio/_core/_io_windows.py index 6053ff5a9..36dd571a6 100644 --- a/src/trio/_core/_io_windows.py +++ b/src/trio/_core/_io_windows.py @@ -710,9 +710,9 @@ def _refresh_afd(self, base_handle: Handle) -> None: kernel32.DeviceIoControl( afd_group.handle, IoControlCodes.IOCTL_AFD_POLL, - cast(ffi.CData, poll_info), + cast(CData, poll_info), ffi.sizeof("AFD_POLL_INFO"), - cast(ffi.CData, poll_info), + cast(CData, poll_info), ffi.sizeof("AFD_POLL_INFO"), ffi.NULL, lpOverlapped, From 0f999b82fb2f01b66ff708a6e3cadc3e95fcecfe Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 28 Oct 2024 14:42:58 -0500 Subject: [PATCH 34/52] Fix cast again --- src/trio/_core/_io_windows.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/trio/_core/_io_windows.py b/src/trio/_core/_io_windows.py index 36dd571a6..bd84a483c 100644 --- a/src/trio/_core/_io_windows.py +++ b/src/trio/_core/_io_windows.py @@ -24,6 +24,7 @@ AFDPollFlags, CData, CompletionModes, + CType, ErrorCodes, FileFlags, Handle, @@ -710,9 +711,9 @@ def _refresh_afd(self, base_handle: Handle) -> None: kernel32.DeviceIoControl( afd_group.handle, IoControlCodes.IOCTL_AFD_POLL, - cast(CData, poll_info), + cast(CType, poll_info), ffi.sizeof("AFD_POLL_INFO"), - cast(CData, poll_info), + cast(CType, poll_info), ffi.sizeof("AFD_POLL_INFO"), ffi.NULL, lpOverlapped, From ac280e225ed9f6d21d77e217e3faa712ad31002f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 00:02:51 +0000 Subject: [PATCH 35/52] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.7.0 → v0.7.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.0...v0.7.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6d37c6c39..d0d758b97 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.0 + rev: v0.7.1 hooks: - id: ruff types: [file] From 50adccbe4338ade6638d286aea31f5f7aed2faf2 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 30 Oct 2024 00:14:04 -0500 Subject: [PATCH 36/52] Clarify comments and get rid of more `Any`s Co-authored-by: John Litborn <11260241+jakkdl@users.noreply.github.com> --- src/trio/_core/_io_windows.py | 12 +++++++----- src/trio/_core/_ki.py | 7 +++---- src/trio/_core/_run.py | 2 ++ src/trio/_core/_tests/test_ki.py | 2 +- src/trio/_core/_tests/test_run.py | 4 ++-- src/trio/_socket.py | 24 ++++++++++-------------- 6 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/trio/_core/_io_windows.py b/src/trio/_core/_io_windows.py index bd84a483c..c4325a286 100644 --- a/src/trio/_core/_io_windows.py +++ b/src/trio/_core/_io_windows.py @@ -250,17 +250,19 @@ class AFDWaiters: current_op: AFDPollOp | None = None -class AFDHandle(Protocol): +# Just used for internal type checking. +class _AFDHandle(Protocol): Handle: Handle Status: int Events: int -class AFDPollInfo(Protocol): +# Just used for internal type checking. +class _AFDPollInfo(Protocol): Timeout: int NumberOfHandles: int Exclusive: int - Handles: list[AFDHandle] + Handles: list[_AFDHandle] # We also need to bundle up all the info for a single op into a standalone @@ -269,7 +271,7 @@ class AFDPollInfo(Protocol): @attrs.frozen(eq=False) class AFDPollOp: lpOverlapped: CData - poll_info: AFDPollInfo + poll_info: _AFDPollInfo waiters: AFDWaiters afd_group: AFDGroup @@ -698,7 +700,7 @@ def _refresh_afd(self, base_handle: Handle) -> None: lpOverlapped = ffi.new("LPOVERLAPPED") - poll_info = cast(AFDPollInfo, ffi.new("AFD_POLL_INFO *")) + poll_info = cast(_AFDPollInfo, ffi.new("AFD_POLL_INFO *")) poll_info.Timeout = 2**63 - 1 # INT64_MAX poll_info.NumberOfHandles = 1 poll_info.Exclusive = 0 diff --git a/src/trio/_core/_ki.py b/src/trio/_core/_ki.py index 79d784537..46a7fdf70 100644 --- a/src/trio/_core/_ki.py +++ b/src/trio/_core/_ki.py @@ -4,7 +4,7 @@ import sys import types import weakref -from typing import TYPE_CHECKING, Any, Generic, Protocol, TypeVar +from typing import TYPE_CHECKING, Generic, Protocol, TypeVar import attrs @@ -85,11 +85,10 @@ class _IdRef(weakref.ref[_T]): __slots__ = ("_hash",) _hash: int - # Explicit "Any" is not allowed - def __new__( # type: ignore[misc] + def __new__( cls, ob: _T, - callback: Callable[[Self], Any] | None = None, + callback: Callable[[Self], object] | None = None, /, ) -> Self: self: Self = weakref.ref.__new__(cls, ob, callback) diff --git a/src/trio/_core/_run.py b/src/trio/_core/_run.py index 308333a49..892eb9df6 100644 --- a/src/trio/_core/_run.py +++ b/src/trio/_core/_run.py @@ -1281,6 +1281,7 @@ def start_soon( """ GLOBAL_RUN_CONTEXT.runner.spawn_impl(async_fn, args, self, name) + # Typing changes blocked by https://github.com/python/mypy/pull/17512 # Explicit "Any" is not allowed async def start( # type: ignore[misc] self, @@ -2413,6 +2414,7 @@ def run( raise AssertionError(runner.main_task_outcome) +# Explicit .../"Any" not allowed def start_guest_run( # type: ignore[misc] async_fn: Callable[..., Awaitable[RetT]], *args: object, diff --git a/src/trio/_core/_tests/test_ki.py b/src/trio/_core/_tests/test_ki.py index c25a54f19..823c7aab0 100644 --- a/src/trio/_core/_tests/test_ki.py +++ b/src/trio/_core/_tests/test_ki.py @@ -678,7 +678,7 @@ async def _consume_async_generator(agen: AsyncGenerator[None, None]) -> None: await agen.aclose() -# Explicit "Any" is not allowed +# Explicit .../"Any" is not allowed def _consume_function_for_coverage( # type: ignore[misc] fn: Callable[..., object], ) -> None: diff --git a/src/trio/_core/_tests/test_run.py b/src/trio/_core/_tests/test_run.py index aafcf9208..7b3958804 100644 --- a/src/trio/_core/_tests/test_run.py +++ b/src/trio/_core/_tests/test_run.py @@ -1648,7 +1648,7 @@ async def func1(expected: str) -> None: async def func2() -> None: # pragma: no cover pass - # Explicit "Any" is not allowed + # Explicit .../"Any" is not allowed async def check( # type: ignore[misc] spawn_fn: Callable[..., object], ) -> None: @@ -1686,7 +1686,7 @@ async def test_current_effective_deadline(mock_clock: _core.MockClock) -> None: def test_nice_error_on_bad_calls_to_run_or_spawn() -> None: - # Explicit "Any" is not allowed + # Explicit .../"Any" is not allowed def bad_call_run( # type: ignore[misc] func: Callable[..., Awaitable[object]], *args: tuple[object, ...], diff --git a/src/trio/_socket.py b/src/trio/_socket.py index 0929874e9..5835a4d75 100644 --- a/src/trio/_socket.py +++ b/src/trio/_socket.py @@ -710,26 +710,24 @@ def recvfrom_into( not TYPE_CHECKING and hasattr(_stdlib_socket.socket, "recvmsg") ): - # Explicit "Any" is not allowed - def recvmsg( # type: ignore[misc] + def recvmsg( __self, __bufsize: int, __ancbufsize: int = 0, __flags: int = 0, - ) -> Awaitable[tuple[bytes, list[tuple[int, int, bytes]], int, Any]]: + ) -> Awaitable[tuple[bytes, list[tuple[int, int, bytes]], int, object]]: raise NotImplementedError if sys.platform != "win32" or ( not TYPE_CHECKING and hasattr(_stdlib_socket.socket, "recvmsg_into") ): - # Explicit "Any" is not allowed - def recvmsg_into( # type: ignore[misc] + def recvmsg_into( __self, __buffers: Iterable[Buffer], __ancbufsize: int = 0, __flags: int = 0, - ) -> Awaitable[tuple[int, list[tuple[int, int, bytes]], int, Any]]: + ) -> Awaitable[tuple[int, list[tuple[int, int, bytes]], int, object]]: raise NotImplementedError def send(__self, __bytes: Buffer, __flags: int = 0) -> Awaitable[int]: @@ -1193,13 +1191,12 @@ def recvfrom_into( ): if TYPE_CHECKING: - # Explicit "Any" is not allowed - def recvmsg( # type: ignore[misc] + def recvmsg( __self, __bufsize: int, __ancbufsize: int = 0, __flags: int = 0, - ) -> Awaitable[tuple[bytes, list[tuple[int, int, bytes]], int, Any]]: ... + ) -> Awaitable[tuple[bytes, list[tuple[int, int, bytes]], int, object]]: ... recvmsg = _make_simple_sock_method_wrapper( _stdlib_socket.socket.recvmsg, @@ -1216,13 +1213,12 @@ def recvmsg( # type: ignore[misc] ): if TYPE_CHECKING: - # Explicit "Any" is not allowed - def recvmsg_into( # type: ignore[misc] + def recvmsg_into( __self, __buffers: Iterable[Buffer], __ancbufsize: int = 0, __flags: int = 0, - ) -> Awaitable[tuple[int, list[tuple[int, int, bytes]], int, Any]]: ... + ) -> Awaitable[tuple[int, list[tuple[int, int, bytes]], int, object]]: ... recvmsg_into = _make_simple_sock_method_wrapper( _stdlib_socket.socket.recvmsg_into, @@ -1262,8 +1258,8 @@ async def sendto( __address: tuple[object, ...] | str | Buffer, ) -> int: ... - @_wraps(_stdlib_socket.socket.sendto, assigned=(), updated=()) # type: ignore[misc] - async def sendto(self, *args: Any) -> int: + @_wraps(_stdlib_socket.socket.sendto, assigned=(), updated=()) + async def sendto(self, *args: object) -> int: """Similar to :meth:`socket.socket.sendto`, but async.""" # args is: data[, flags], address # and kwargs are not accepted From 3a320c33a922c23376e4165e6e55c87e3dacf096 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 30 Oct 2024 00:17:33 -0500 Subject: [PATCH 37/52] Update src/trio/_tests/test_socket.py Co-authored-by: John Litborn <11260241+jakkdl@users.noreply.github.com> --- src/trio/_tests/test_socket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trio/_tests/test_socket.py b/src/trio/_tests/test_socket.py index df7f5b33b..50fecae1f 100644 --- a/src/trio/_tests/test_socket.py +++ b/src/trio/_tests/test_socket.py @@ -41,7 +41,7 @@ class MonkeypatchedGAI: - # Explicit "Any" is not allowed + # Explicit .../"Any" is not allowed def __init__( # type: ignore[misc] self, orig_getaddrinfo: Callable[..., GetAddrInfoResponse], From 03f1c4ecd3780f5df23e98e3b5e05e2480ef0de5 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 30 Oct 2024 00:20:46 -0500 Subject: [PATCH 38/52] Apply suggestions from code review Co-authored-by: John Litborn <11260241+jakkdl@users.noreply.github.com> --- src/trio/_util.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/trio/_util.py b/src/trio/_util.py index 9b49e3bfa..b354fbf5d 100644 --- a/src/trio/_util.py +++ b/src/trio/_util.py @@ -305,7 +305,7 @@ def open_memory_channel(max_buffer_size: int) -> Tuple[ but at least it becomes possible to write those. """ - # Explicit "Any" is not allowed + # Explicit .../"Any" is not allowed def __init__( # type: ignore[misc] self, fn: Callable[..., RetT], @@ -402,10 +402,10 @@ def name_asyncgen(agen: AsyncGeneratorType[object, NoReturn]) -> str: # work around a pyright error if TYPE_CHECKING: - # Explicit "Any" is not allowed + # Explicit .../"Any" is not allowed Fn = TypeVar("Fn", bound=Callable[..., object]) # type: ignore[misc] - # Explicit "Any" is not allowed + # Explicit .../"Any" is not allowed def wraps( # type: ignore[misc] wrapped: Callable[..., object], assigned: Sequence[str] = ..., From 33f1caa2d65d8a8b23a01fd363e199c8b37bc562 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 30 Oct 2024 00:23:09 -0500 Subject: [PATCH 39/52] Apply suggestions from code review Co-authored-by: John Litborn <11260241+jakkdl@users.noreply.github.com> --- src/trio/_path.py | 2 +- src/trio/_tests/test_subprocess.py | 2 +- src/trio/_threads.py | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/trio/_path.py b/src/trio/_path.py index 2e42328f6..a58136b75 100644 --- a/src/trio/_path.py +++ b/src/trio/_path.py @@ -30,7 +30,7 @@ T = TypeVar("T") -# Explicit "Any" is not allowed +# Explicit .../"Any" is not allowed def _wraps_async( # type: ignore[misc] wrapped: Callable[..., object], ) -> Callable[[Callable[P, T]], Callable[P, Awaitable[T]]]: diff --git a/src/trio/_tests/test_subprocess.py b/src/trio/_tests/test_subprocess.py index e2c6febd1..e58a40f51 100644 --- a/src/trio/_tests/test_subprocess.py +++ b/src/trio/_tests/test_subprocess.py @@ -115,7 +115,7 @@ async def run_process_in_nursery(*args: Any, **kwargs: Any) -> AsyncIterator[Pro ids=["open_process", "run_process in nursery"], ) -# Explicit "Any" is not allowed +# Explicit .../"Any" is not allowed BackgroundProcessType: TypeAlias = Callable[ # type: ignore[misc] ..., AbstractAsyncContextManager[Process], diff --git a/src/trio/_threads.py b/src/trio/_threads.py index 2741f1a6f..458d42729 100644 --- a/src/trio/_threads.py +++ b/src/trio/_threads.py @@ -207,9 +207,8 @@ def in_trio_thread() -> None: @attrs.frozen(eq=False, slots=False) -# Explicit "Any" is not allowed +# Explicit .../"Any" is not allowed class RunSync(Generic[RetT]): # type: ignore[misc] - # Explicit "Any" is not allowed fn: Callable[..., RetT] # type: ignore[misc] args: tuple[object, ...] context: contextvars.Context = attrs.field( From 854c5cd83757b57fb370072c8728b4934f16703a Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 30 Oct 2024 09:34:21 -0500 Subject: [PATCH 40/52] Update src/trio/_threads.py Co-authored-by: John Litborn <11260241+jakkdl@users.noreply.github.com> --- src/trio/_threads.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/trio/_threads.py b/src/trio/_threads.py index 458d42729..7afd7b612 100644 --- a/src/trio/_threads.py +++ b/src/trio/_threads.py @@ -146,9 +146,8 @@ class ThreadPlaceholder: # Types for the to_thread_run_sync message loop @attrs.frozen(eq=False, slots=False) -# Explicit "Any" is not allowed +# Explicit .../"Any" is not allowed class Run(Generic[RetT]): # type: ignore[misc] - # Explicit "Any" is not allowed afn: Callable[..., Awaitable[RetT]] # type: ignore[misc] args: tuple[object, ...] context: contextvars.Context = attrs.field( From bcd3f54f89077e3bd7ade545127cdcfa40ee95b4 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 30 Oct 2024 10:27:50 -0500 Subject: [PATCH 41/52] Improve type annotations Co-authored-by: John Litborn <11260241+jakkdl@users.noreply.github.com> --- src/trio/_tests/test_highlevel_ssl_helpers.py | 10 +-- src/trio/_tests/test_socket.py | 86 +++++++++++-------- src/trio/_tests/test_testing_raisesgroup.py | 6 +- 3 files changed, 58 insertions(+), 44 deletions(-) diff --git a/src/trio/_tests/test_highlevel_ssl_helpers.py b/src/trio/_tests/test_highlevel_ssl_helpers.py index 4dc904910..e32e1957b 100644 --- a/src/trio/_tests/test_highlevel_ssl_helpers.py +++ b/src/trio/_tests/test_highlevel_ssl_helpers.py @@ -1,7 +1,7 @@ from __future__ import annotations from functools import partial -from typing import TYPE_CHECKING, Any, NoReturn, cast +from typing import TYPE_CHECKING, NoReturn, cast import attrs import pytest @@ -65,11 +65,11 @@ async def getaddrinfo( ]: return [(AF_INET, SOCK_STREAM, IPPROTO_TCP, "", self.sockaddr)] - # Explicit "Any" is not allowed - async def getnameinfo( # type: ignore[misc] + async def getnameinfo( self, - *args: Any, - ) -> NoReturn: # pragma: no cover + sockaddr: tuple[str, int] | tuple[str, int, int, int], + flags: int, + ) -> NoReturn: raise NotImplementedError diff --git a/src/trio/_tests/test_socket.py b/src/trio/_tests/test_socket.py index 50fecae1f..7e83e3d48 100644 --- a/src/trio/_tests/test_socket.py +++ b/src/trio/_tests/test_socket.py @@ -8,14 +8,14 @@ import tempfile from pathlib import Path from socket import AddressFamily, SocketKind -from typing import TYPE_CHECKING, Any, Callable, Union +from typing import TYPE_CHECKING, Callable, Union, cast import attrs import pytest from .. import _core, socket as tsocket from .._core._tests.tutil import binds_ipv6, creates_ipv6 -from .._socket import _NUMERIC_ONLY, SocketType, _SocketType, _try_sync +from .._socket import _NUMERIC_ONLY, AddressFormat, SocketType, _SocketType, _try_sync from ..testing import assert_checkpoints, wait_all_tasks_blocked if TYPE_CHECKING: @@ -41,50 +41,64 @@ class MonkeypatchedGAI: + __slots__ = ("_orig_getaddrinfo", "_responses", "record") + # Explicit .../"Any" is not allowed def __init__( # type: ignore[misc] self, orig_getaddrinfo: Callable[..., GetAddrInfoResponse], ) -> None: self._orig_getaddrinfo = orig_getaddrinfo - self._responses: dict[tuple[Any, ...], GetAddrInfoResponse | str] = {} # type: ignore[misc] - self.record: list[tuple[Any, ...]] = [] # type: ignore[misc] + self._responses: dict[ + tuple[str | int | bytes | None, ...], + GetAddrInfoResponse | str, + ] = {} + self.record: list[tuple[str | int | bytes | None, ...]] = [] # get a normalized getaddrinfo argument tuple - # Explicit "Any" is not allowed - def _frozenbind( # type: ignore[misc] + def _frozenbind( self, - *args: Any, - **kwargs: Any, - ) -> tuple[Any, ...]: + host: str | bytes | None, + port: str | bytes | int | None, + family: int = 0, + type: int = 0, + proto: int = 0, + flags: int = 0, + ) -> tuple[str | int | bytes | None, ...]: sig = inspect.signature(self._orig_getaddrinfo) - bound = sig.bind(*args, **kwargs) + bound = sig.bind(host, port, family, proto, flags) bound.apply_defaults() frozenbound = bound.args assert not bound.kwargs return frozenbound - # Explicit "Any" is not allowed - def set( # type: ignore[misc] + def set( self, response: GetAddrInfoResponse | str, - *args: Any, - **kwargs: Any, + host: str | bytes | None, + port: str | bytes | int | None, + family: int = 0, + type: int = 0, + proto: int = 0, + flags: int = 0, ) -> None: - self._responses[self._frozenbind(*args, **kwargs)] = response + self._responses[self._frozenbind(host, port, family, proto, flags)] = response - # Explicit "Any" is not allowed - def getaddrinfo( # type: ignore[misc] + def getaddrinfo( self, - *args: Any, - **kwargs: Any, + host: str | bytes | None, + port: str | bytes | int | None, + family: int = 0, + type: int = 0, + proto: int = 0, + flags: int = 0, ) -> GetAddrInfoResponse | str: - bound = self._frozenbind(*args, **kwargs) + bound = self._frozenbind(host, port, family, proto, flags) self.record.append(bound) if bound in self._responses: return self._responses[bound] - elif bound[-1] & stdlib_socket.AI_NUMERICHOST: - return self._orig_getaddrinfo(*args, **kwargs) + elif flags & stdlib_socket.AI_NUMERICHOST: + return self._orig_getaddrinfo(host, port, family, proto, flags) else: raise RuntimeError(f"gai called with unexpected arguments {bound}") @@ -601,8 +615,7 @@ def assert_eq( # local=True/local=False should work the same: for local in [False, True]: - # Explicit "Any" is not allowed - async def res( # type: ignore[misc] + async def res( args: ( tuple[str, int] | tuple[str, int, int] @@ -611,11 +624,13 @@ async def res( # type: ignore[misc] | tuple[str, str, int] | tuple[str, str, int, int] ), - ) -> Any: - return await sock._resolve_address_nocp( + ) -> tuple[str | int, ...]: + value = await sock._resolve_address_nocp( args, local=local, # noqa: B023 # local is not bound in function definition ) + assert isinstance(value, tuple) + return cast(tuple[Union[str, int], ...], value) assert_eq(await res((addrs.arbitrary, "http")), (addrs.arbitrary, 80)) if v6: @@ -810,11 +825,9 @@ async def test_SocketType_connect_paths() -> None: # nose -- and then swap it back out again before we hit # wait_socket_writable, which insists on a real socket. class CancelSocket(stdlib_socket.socket): - # Explicit "Any" is not allowed - def connect( # type: ignore[misc] + def connect( self, - *args: Any, - **kwargs: Any, + address: AddressFormat, ) -> None: # accessing private method only available in _SocketType assert isinstance(sock, _SocketType) @@ -825,7 +838,7 @@ def connect( # type: ignore[misc] self.family, self.type, ) - sock._sock.connect(*args, **kwargs) + sock._sock.connect(address) # If connect *doesn't* raise, then pretend it did raise BlockingIOError # pragma: no cover @@ -871,11 +884,14 @@ async def test_resolve_address_exception_in_connect_closes_socket() -> None: with _core.CancelScope() as cancel_scope: with tsocket.socket() as sock: - # Explicit "Any" is not allowed - async def _resolve_address_nocp( # type: ignore[misc] + async def _resolve_address_nocp( self: _SocketType, - *args: Any, - **kwargs: Any, + host: str | bytes | None, + port: str | bytes | int | None, + family: int = 0, + type: int = 0, + proto: int = 0, + flags: int = 0, ) -> None: cancel_scope.cancel() await _core.checkpoint() diff --git a/src/trio/_tests/test_testing_raisesgroup.py b/src/trio/_tests/test_testing_raisesgroup.py index d0e89c22d..6673ed00d 100644 --- a/src/trio/_tests/test_testing_raisesgroup.py +++ b/src/trio/_tests/test_testing_raisesgroup.py @@ -3,7 +3,6 @@ import re import sys from types import TracebackType -from typing import Any import pytest @@ -235,10 +234,9 @@ def test_RaisesGroup_matches() -> None: def test_message() -> None: - # Explicit "Any" is not allowed - def check_message( # type: ignore[misc] + def check_message( message: str, - body: RaisesGroup[Any], + body: RaisesGroup[object], ) -> None: with pytest.raises( AssertionError, From ee0322ac7491455ee9c34ad5e43ddcee3c9898e9 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 30 Oct 2024 13:03:13 -0500 Subject: [PATCH 42/52] Forgot `type` and fix more type issues --- src/trio/_tests/test_socket.py | 24 ++++++++++----------- src/trio/_tests/test_testing_raisesgroup.py | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/trio/_tests/test_socket.py b/src/trio/_tests/test_socket.py index 7e83e3d48..1c12ab977 100644 --- a/src/trio/_tests/test_socket.py +++ b/src/trio/_tests/test_socket.py @@ -66,7 +66,7 @@ def _frozenbind( flags: int = 0, ) -> tuple[str | int | bytes | None, ...]: sig = inspect.signature(self._orig_getaddrinfo) - bound = sig.bind(host, port, family, proto, flags) + bound = sig.bind(host, port, family, type, proto, flags) bound.apply_defaults() frozenbound = bound.args assert not bound.kwargs @@ -82,7 +82,9 @@ def set( proto: int = 0, flags: int = 0, ) -> None: - self._responses[self._frozenbind(host, port, family, proto, flags)] = response + self._responses[self._frozenbind(host, port, family, type, proto, flags)] = ( + response + ) def getaddrinfo( self, @@ -93,12 +95,12 @@ def getaddrinfo( proto: int = 0, flags: int = 0, ) -> GetAddrInfoResponse | str: - bound = self._frozenbind(host, port, family, proto, flags) + bound = self._frozenbind(host, port, family, type, proto, flags) self.record.append(bound) if bound in self._responses: return self._responses[bound] elif flags & stdlib_socket.AI_NUMERICHOST: - return self._orig_getaddrinfo(host, port, family, proto, flags) + return self._orig_getaddrinfo(host, port, family, type, proto, flags) else: raise RuntimeError(f"gai called with unexpected arguments {bound}") @@ -885,19 +887,17 @@ async def test_resolve_address_exception_in_connect_closes_socket() -> None: with tsocket.socket() as sock: async def _resolve_address_nocp( - self: _SocketType, - host: str | bytes | None, - port: str | bytes | int | None, - family: int = 0, - type: int = 0, - proto: int = 0, - flags: int = 0, + address: AddressFormat, + *, + local: bool, ) -> None: + assert address == "" + assert not local cancel_scope.cancel() await _core.checkpoint() assert isinstance(sock, _SocketType) - sock._resolve_address_nocp = _resolve_address_nocp # type: ignore[method-assign, assignment] + sock._resolve_address_nocp = _resolve_address_nocp # type: ignore[method-assign] with assert_checkpoints(): with pytest.raises(_core.Cancelled): await sock.connect("") diff --git a/src/trio/_tests/test_testing_raisesgroup.py b/src/trio/_tests/test_testing_raisesgroup.py index 6673ed00d..7b2fe4417 100644 --- a/src/trio/_tests/test_testing_raisesgroup.py +++ b/src/trio/_tests/test_testing_raisesgroup.py @@ -236,7 +236,7 @@ def test_RaisesGroup_matches() -> None: def test_message() -> None: def check_message( message: str, - body: RaisesGroup[object], + body: RaisesGroup[BaseException], ) -> None: with pytest.raises( AssertionError, From 9005f98b65e2acb8bf5ecfa442a4baa8b82faf19 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 30 Oct 2024 13:21:37 -0500 Subject: [PATCH 43/52] Add typing to `orig_getaddrinfo` --- src/trio/_tests/test_socket.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/trio/_tests/test_socket.py b/src/trio/_tests/test_socket.py index 1c12ab977..628a70c1f 100644 --- a/src/trio/_tests/test_socket.py +++ b/src/trio/_tests/test_socket.py @@ -8,7 +8,7 @@ import tempfile from pathlib import Path from socket import AddressFamily, SocketKind -from typing import TYPE_CHECKING, Callable, Union, cast +from typing import TYPE_CHECKING, Union, cast import attrs import pytest @@ -19,6 +19,8 @@ from ..testing import assert_checkpoints, wait_all_tasks_blocked if TYPE_CHECKING: + from collections.abc import Callable + from typing_extensions import TypeAlias from .._highlevel_socket import SocketStream @@ -43,10 +45,12 @@ class MonkeypatchedGAI: __slots__ = ("_orig_getaddrinfo", "_responses", "record") - # Explicit .../"Any" is not allowed - def __init__( # type: ignore[misc] + def __init__( self, - orig_getaddrinfo: Callable[..., GetAddrInfoResponse], + orig_getaddrinfo: Callable[ + [str | bytes | None, str | bytes | int | None, int, int, int, int], + GetAddrInfoResponse, + ], ) -> None: self._orig_getaddrinfo = orig_getaddrinfo self._responses: dict[ From c48044955be25f57d31b569f2c779503a59606a9 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 30 Oct 2024 13:25:43 -0500 Subject: [PATCH 44/52] Add full typing for `_responses` and `record` --- src/trio/_tests/test_socket.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/trio/_tests/test_socket.py b/src/trio/_tests/test_socket.py index 628a70c1f..fda7eb54d 100644 --- a/src/trio/_tests/test_socket.py +++ b/src/trio/_tests/test_socket.py @@ -33,9 +33,18 @@ Union[tuple[str, int], tuple[str, int, int, int]], ] GetAddrInfoResponse: TypeAlias = list[GaiTuple] + GetAddrInfoArgs: TypeAlias = tuple[ + str | bytes | None, + str | bytes | int | None, + int, + int, + int, + int, + ] else: GaiTuple: object GetAddrInfoResponse = object + GetAddrInfoArgs = object ################################################################ # utils @@ -54,10 +63,10 @@ def __init__( ) -> None: self._orig_getaddrinfo = orig_getaddrinfo self._responses: dict[ - tuple[str | int | bytes | None, ...], + GetAddrInfoArgs, GetAddrInfoResponse | str, ] = {} - self.record: list[tuple[str | int | bytes | None, ...]] = [] + self.record: list[GetAddrInfoArgs] = [] # get a normalized getaddrinfo argument tuple def _frozenbind( From ba24f74fb9003fa56d55f4644e7dc6dfd507a7cc Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 30 Oct 2024 13:30:30 -0500 Subject: [PATCH 45/52] Fix type issues --- src/trio/_tests/test_socket.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/trio/_tests/test_socket.py b/src/trio/_tests/test_socket.py index fda7eb54d..e09fbc36d 100644 --- a/src/trio/_tests/test_socket.py +++ b/src/trio/_tests/test_socket.py @@ -34,8 +34,8 @@ ] GetAddrInfoResponse: TypeAlias = list[GaiTuple] GetAddrInfoArgs: TypeAlias = tuple[ - str | bytes | None, - str | bytes | int | None, + Union[str, bytes, None], + Union[str, bytes, int, None], int, int, int, @@ -77,7 +77,7 @@ def _frozenbind( type: int = 0, proto: int = 0, flags: int = 0, - ) -> tuple[str | int | bytes | None, ...]: + ) -> GetAddrInfoArgs: sig = inspect.signature(self._orig_getaddrinfo) bound = sig.bind(host, port, family, type, proto, flags) bound.apply_defaults() From 9d6e134d3256c811ea311322407058e102a8918e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 01:05:49 +0000 Subject: [PATCH 46/52] Dependency updates (#3125) --- docs-requirements.txt | 16 +++++++-------- test-requirements.txt | 47 ++++++++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/docs-requirements.txt b/docs-requirements.txt index ee4152f18..9698e5785 100644 --- a/docs-requirements.txt +++ b/docs-requirements.txt @@ -1,6 +1,6 @@ # This file was autogenerated by uv via the following command: # uv pip compile --universal --python-version=3.11 docs-requirements.in -o docs-requirements.txt -alabaster==0.7.16 +alabaster==1.0.0 # via sphinx attrs==24.2.0 # via @@ -16,7 +16,7 @@ cffi==1.17.1 ; platform_python_implementation != 'PyPy' or os_name == 'nt' # via # -r docs-requirements.in # cryptography -charset-normalizer==3.3.2 +charset-normalizer==3.4.0 # via requests click==8.1.7 # via towncrier @@ -24,9 +24,9 @@ colorama==0.4.6 ; sys_platform == 'win32' or platform_system == 'Windows' # via # click # sphinx -cryptography==43.0.1 +cryptography==43.0.3 # via pyopenssl -docutils==0.20.1 +docutils==0.21.2 # via # sphinx # sphinx-rtd-theme @@ -38,14 +38,14 @@ idna==3.10 # requests imagesize==1.4.1 # via sphinx -immutables==0.20 +immutables==0.21 # via -r docs-requirements.in jinja2==3.1.4 # via # -r docs-requirements.in # sphinx # towncrier -markupsafe==2.1.5 +markupsafe==3.0.2 # via jinja2 outcome==1.3.0.post0 # via -r docs-requirements.in @@ -67,7 +67,7 @@ sortedcontainers==2.4.0 # via -r docs-requirements.in soupsieve==2.6 # via beautifulsoup4 -sphinx==7.4.7 +sphinx==8.1.3 # via # -r docs-requirements.in # sphinx-codeautolink @@ -79,7 +79,7 @@ sphinx-codeautolink==0.15.2 # via -r docs-requirements.in sphinx-hoverxref==1.4.1 # via -r docs-requirements.in -sphinx-rtd-theme==3.0.0 +sphinx-rtd-theme==3.0.1 # via -r docs-requirements.in sphinxcontrib-applehelp==2.0.0 # via sphinx diff --git a/test-requirements.txt b/test-requirements.txt index 314eaf4b9..23ed36462 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,10 +1,10 @@ # This file was autogenerated by uv via the following command: # uv pip compile --universal --python-version=3.9 test-requirements.in -o test-requirements.txt -alabaster==0.7.13 +alabaster==0.7.16 # via sphinx astor==0.8.1 # via -r test-requirements.in -astroid==3.2.4 +astroid==3.3.5 # via pylint async-generator==1.10 # via -r test-requirements.in @@ -14,7 +14,7 @@ attrs==24.2.0 # outcome babel==2.16.0 # via sphinx -black==24.8.0 ; implementation_name == 'cpython' +black==24.10.0 ; implementation_name == 'cpython' # via -r test-requirements.in certifi==2024.8.30 # via requests @@ -22,7 +22,7 @@ cffi==1.17.1 ; platform_python_implementation != 'PyPy' or os_name == 'nt' # via # -r test-requirements.in # cryptography -charset-normalizer==3.3.2 +charset-normalizer==3.4.0 # via requests click==8.1.7 ; implementation_name == 'cpython' # via black @@ -34,9 +34,9 @@ colorama==0.4.6 ; (implementation_name != 'cpython' and sys_platform == 'win32') # pylint # pytest # sphinx -coverage==7.6.1 +coverage==7.6.4 # via -r test-requirements.in -cryptography==43.0.1 +cryptography==43.0.3 # via # -r test-requirements.in # pyopenssl @@ -44,7 +44,7 @@ cryptography==43.0.1 # types-pyopenssl dill==0.3.9 # via pylint -docutils==0.20.1 +docutils==0.21.2 # via sphinx exceptiongroup==1.2.2 ; python_full_version < '3.11' # via @@ -67,11 +67,11 @@ jedi==0.19.1 ; implementation_name == 'cpython' # via -r test-requirements.in jinja2==3.1.4 # via sphinx -markupsafe==2.1.5 +markupsafe==3.0.2 # via jinja2 mccabe==0.7.0 # via pylint -mypy==1.11.2 +mypy==1.13.0 # via -r test-requirements.in mypy-extensions==1.0.0 # via @@ -101,17 +101,17 @@ pycparser==2.22 ; platform_python_implementation != 'PyPy' or os_name == 'nt' # via cffi pygments==2.18.0 # via sphinx -pylint==3.2.7 +pylint==3.3.1 # via -r test-requirements.in pyopenssl==24.2.1 # via -r test-requirements.in -pyright==1.1.382.post1 +pyright==1.1.387 # via -r test-requirements.in pytest==8.3.3 # via -r test-requirements.in requests==2.32.3 # via sphinx -ruff==0.6.8 +ruff==0.7.1 # via -r test-requirements.in sniffio==1.3.1 # via -r test-requirements.in @@ -119,39 +119,40 @@ snowballstemmer==2.2.0 # via sphinx sortedcontainers==2.4.0 # via -r test-requirements.in -sphinx==7.1.2 +sphinx==7.4.7 # via -r test-requirements.in -sphinxcontrib-applehelp==1.0.4 +sphinxcontrib-applehelp==2.0.0 # via sphinx -sphinxcontrib-devhelp==1.0.2 +sphinxcontrib-devhelp==2.0.0 # via sphinx -sphinxcontrib-htmlhelp==2.0.1 +sphinxcontrib-htmlhelp==2.1.0 # via sphinx sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.3 +sphinxcontrib-qthelp==2.0.0 # via sphinx -sphinxcontrib-serializinghtml==1.1.5 +sphinxcontrib-serializinghtml==2.0.0 # via sphinx -tomli==2.0.1 ; python_full_version < '3.11' +tomli==2.0.2 ; python_full_version < '3.11' # via # black # mypy # pylint # pytest + # sphinx tomlkit==0.13.2 # via pylint -trustme==1.1.0 +trustme==1.2.0 # via -r test-requirements.in types-cffi==1.16.0.20240331 # via # -r test-requirements.in # types-pyopenssl -types-docutils==0.21.0.20240907 +types-docutils==0.21.0.20241005 # via -r test-requirements.in types-pyopenssl==24.1.0.20240722 # via -r test-requirements.in -types-setuptools==75.1.0.20240917 +types-setuptools==75.2.0.20241025 # via types-cffi typing-extensions==4.12.2 # via @@ -163,7 +164,7 @@ typing-extensions==4.12.2 # pyright urllib3==2.2.3 # via requests -uv==0.4.17 +uv==0.4.29 # via -r test-requirements.in zipp==3.20.2 ; python_full_version < '3.10' # via importlib-metadata From 4447dad5333b10304684a4bcf6208c40d4e0004c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 23:56:56 +0000 Subject: [PATCH 47/52] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.7.1 → v0.7.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.1...v0.7.2) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d0d758b97..fe316fbf4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.1 + rev: v0.7.2 hooks: - id: ruff types: [file] From 5c14ddb0ce7f22e6b38f3dbcbb655fae06759002 Mon Sep 17 00:00:00 2001 From: EXPLOSION Date: Sat, 9 Nov 2024 01:43:11 -0500 Subject: [PATCH 48/52] Get rid of `signal_raise` (#3126) * Get rid of `signal_raise` * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/trio/_core/_tests/test_guest_mode.py | 7 ++- src/trio/_core/_tests/test_ki.py | 3 +- src/trio/_signals.py | 6 +-- src/trio/_tests/test_repl.py | 3 +- src/trio/_tests/test_signals.py | 29 ++++++------ src/trio/_tests/test_util.py | 16 ------- src/trio/_util.py | 56 ------------------------ 7 files changed, 22 insertions(+), 98 deletions(-) diff --git a/src/trio/_core/_tests/test_guest_mode.py b/src/trio/_core/_tests/test_guest_mode.py index 678874fec..1aae101b0 100644 --- a/src/trio/_core/_tests/test_guest_mode.py +++ b/src/trio/_core/_tests/test_guest_mode.py @@ -28,7 +28,6 @@ import trio.testing from trio.abc import Clock, Instrument -from ..._util import signal_raise from .tutil import gc_collect_harder, restore_unraisablehook if TYPE_CHECKING: @@ -605,10 +604,10 @@ def test_guest_mode_ki() -> None: # Check SIGINT in Trio func and in host func async def trio_main(in_host: InHost) -> None: with pytest.raises(KeyboardInterrupt): - signal_raise(signal.SIGINT) + signal.raise_signal(signal.SIGINT) # Host SIGINT should get injected into Trio - in_host(partial(signal_raise, signal.SIGINT)) + in_host(partial(signal.raise_signal, signal.SIGINT)) await trio.sleep(10) with pytest.raises(KeyboardInterrupt) as excinfo: @@ -621,7 +620,7 @@ async def trio_main(in_host: InHost) -> None: final_exc = KeyError("whoa") async def trio_main_raising(in_host: InHost) -> NoReturn: - in_host(partial(signal_raise, signal.SIGINT)) + in_host(partial(signal.raise_signal, signal.SIGINT)) raise final_exc with pytest.raises(KeyboardInterrupt) as excinfo: diff --git a/src/trio/_core/_tests/test_ki.py b/src/trio/_core/_tests/test_ki.py index 823c7aab0..67c83e835 100644 --- a/src/trio/_core/_tests/test_ki.py +++ b/src/trio/_core/_tests/test_ki.py @@ -25,7 +25,6 @@ from ..._abc import Instrument from ..._core import _ki from ..._timeouts import sleep -from ..._util import signal_raise from ...testing import wait_all_tasks_blocked if TYPE_CHECKING: @@ -41,7 +40,7 @@ def ki_self() -> None: - signal_raise(signal.SIGINT) + signal.raise_signal(signal.SIGINT) def test_ki_self() -> None: diff --git a/src/trio/_signals.py b/src/trio/_signals.py index 63ee176c1..729c48ad4 100644 --- a/src/trio/_signals.py +++ b/src/trio/_signals.py @@ -7,7 +7,7 @@ import trio -from ._util import ConflictDetector, is_main_thread, signal_raise +from ._util import ConflictDetector, is_main_thread if TYPE_CHECKING: from collections.abc import AsyncIterator, Callable, Generator, Iterable @@ -78,7 +78,7 @@ def __init__(self) -> None: def _add(self, signum: int) -> None: if self._closed: - signal_raise(signum) + signal.raise_signal(signum) else: self._pending[signum] = None self._lot.unpark() @@ -95,7 +95,7 @@ def deliver_next() -> None: if self._pending: signum, _ = self._pending.popitem(last=False) try: - signal_raise(signum) + signal.raise_signal(signum) finally: deliver_next() diff --git a/src/trio/_tests/test_repl.py b/src/trio/_tests/test_repl.py index eba166d7d..be9338ce4 100644 --- a/src/trio/_tests/test_repl.py +++ b/src/trio/_tests/test_repl.py @@ -103,12 +103,11 @@ async def test_KI_interrupts( console = trio._repl.TrioInteractiveConsole(repl_locals=build_locals()) raw_input = build_raw_input( [ - "from trio._util import signal_raise", "import signal, trio, trio.lowlevel", "async def f():", " trio.lowlevel.spawn_system_task(" " trio.to_thread.run_sync," - " signal_raise,signal.SIGINT," + " signal.raise_signal, signal.SIGINT," " )", # just awaiting this kills the test runner?! " await trio.sleep_forever()", " print('should not see this')", diff --git a/src/trio/_tests/test_signals.py b/src/trio/_tests/test_signals.py index 453b1b68f..d149b8657 100644 --- a/src/trio/_tests/test_signals.py +++ b/src/trio/_tests/test_signals.py @@ -10,7 +10,6 @@ from .. import _core from .._signals import _signal_handler, get_pending_signal_count, open_signal_receiver -from .._util import signal_raise if TYPE_CHECKING: from types import FrameType @@ -21,16 +20,16 @@ async def test_open_signal_receiver() -> None: with open_signal_receiver(signal.SIGILL) as receiver: # Raise it a few times, to exercise signal coalescing, both at the # call_soon level and at the SignalQueue level - signal_raise(signal.SIGILL) - signal_raise(signal.SIGILL) + signal.raise_signal(signal.SIGILL) + signal.raise_signal(signal.SIGILL) await _core.wait_all_tasks_blocked() - signal_raise(signal.SIGILL) + signal.raise_signal(signal.SIGILL) await _core.wait_all_tasks_blocked() async for signum in receiver: # pragma: no branch assert signum == signal.SIGILL break assert get_pending_signal_count(receiver) == 0 - signal_raise(signal.SIGILL) + signal.raise_signal(signal.SIGILL) async for signum in receiver: # pragma: no branch assert signum == signal.SIGILL break @@ -101,8 +100,8 @@ async def test_open_signal_receiver_no_starvation() -> None: print(signal.getsignal(signal.SIGILL)) previous = None for _ in range(10): - signal_raise(signal.SIGILL) - signal_raise(signal.SIGFPE) + signal.raise_signal(signal.SIGILL) + signal.raise_signal(signal.SIGFPE) await wait_run_sync_soon_idempotent_queue_barrier() if previous is None: previous = await receiver.__anext__() @@ -134,8 +133,8 @@ def direct_handler(signo: int, frame: FrameType | None) -> None: # before we exit the with block: with _signal_handler({signal.SIGILL, signal.SIGFPE}, direct_handler): with open_signal_receiver(signal.SIGILL, signal.SIGFPE) as receiver: - signal_raise(signal.SIGILL) - signal_raise(signal.SIGFPE) + signal.raise_signal(signal.SIGILL) + signal.raise_signal(signal.SIGFPE) await wait_run_sync_soon_idempotent_queue_barrier() assert delivered_directly == {signal.SIGILL, signal.SIGFPE} delivered_directly.clear() @@ -145,8 +144,8 @@ def direct_handler(signo: int, frame: FrameType | None) -> None: # we exit the with block: with _signal_handler({signal.SIGILL, signal.SIGFPE}, direct_handler): with open_signal_receiver(signal.SIGILL, signal.SIGFPE) as receiver: - signal_raise(signal.SIGILL) - signal_raise(signal.SIGFPE) + signal.raise_signal(signal.SIGILL) + signal.raise_signal(signal.SIGFPE) await wait_run_sync_soon_idempotent_queue_barrier() assert get_pending_signal_count(receiver) == 2 assert delivered_directly == {signal.SIGILL, signal.SIGFPE} @@ -157,14 +156,14 @@ def direct_handler(signo: int, frame: FrameType | None) -> None: print(3) with _signal_handler({signal.SIGILL}, signal.SIG_IGN): with open_signal_receiver(signal.SIGILL) as receiver: - signal_raise(signal.SIGILL) + signal.raise_signal(signal.SIGILL) await wait_run_sync_soon_idempotent_queue_barrier() # test passes if the process reaches this point without dying print(4) with _signal_handler({signal.SIGILL}, signal.SIG_IGN): with open_signal_receiver(signal.SIGILL) as receiver: - signal_raise(signal.SIGILL) + signal.raise_signal(signal.SIGILL) await wait_run_sync_soon_idempotent_queue_barrier() assert get_pending_signal_count(receiver) == 1 # test passes if the process reaches this point without dying @@ -177,8 +176,8 @@ def raise_handler(signum: int, frame: FrameType | None) -> NoReturn: with _signal_handler({signal.SIGILL, signal.SIGFPE}, raise_handler): with pytest.raises(RuntimeError) as excinfo: with open_signal_receiver(signal.SIGILL, signal.SIGFPE) as receiver: - signal_raise(signal.SIGILL) - signal_raise(signal.SIGFPE) + signal.raise_signal(signal.SIGILL) + signal.raise_signal(signal.SIGFPE) await wait_run_sync_soon_idempotent_queue_barrier() assert get_pending_signal_count(receiver) == 2 exc = excinfo.value diff --git a/src/trio/_tests/test_util.py b/src/trio/_tests/test_util.py index 23d16fe84..5036d76e5 100644 --- a/src/trio/_tests/test_util.py +++ b/src/trio/_tests/test_util.py @@ -1,6 +1,5 @@ from __future__ import annotations -import signal import sys import types from typing import TYPE_CHECKING, TypeVar @@ -25,7 +24,6 @@ fixup_module_metadata, generic_function, is_main_thread, - signal_raise, ) from ..testing import wait_all_tasks_blocked @@ -35,20 +33,6 @@ T = TypeVar("T") -def test_signal_raise() -> None: - record = [] - - def handler(signum: int, _: object) -> None: - record.append(signum) - - old = signal.signal(signal.SIGFPE, handler) - try: - signal_raise(signal.SIGFPE) - finally: - signal.signal(signal.SIGFPE, old) - assert record == [signal.SIGFPE] - - async def test_ConflictDetector() -> None: ul1 = ConflictDetector("ul1") ul2 = ConflictDetector("ul2") diff --git a/src/trio/_util.py b/src/trio/_util.py index b354fbf5d..994a4655b 100644 --- a/src/trio/_util.py +++ b/src/trio/_util.py @@ -3,9 +3,7 @@ import collections.abc import inspect -import os import signal -import threading from abc import ABCMeta from collections.abc import Awaitable, Callable, Sequence from functools import update_wrapper @@ -36,60 +34,6 @@ PosArgsT = TypeVarTuple("PosArgsT") -if TYPE_CHECKING: - # Don't type check the implementation below, pthread_kill does not exist on Windows. - def signal_raise(signum: int) -> None: ... - - -# Equivalent to the C function raise(), which Python doesn't wrap -elif os.name == "nt": - # On Windows, os.kill exists but is really weird. - # - # If you give it CTRL_C_EVENT or CTRL_BREAK_EVENT, it tries to deliver - # those using GenerateConsoleCtrlEvent. But I found that when I tried - # to run my test normally, it would freeze waiting... unless I added - # print statements, in which case the test suddenly worked. So I guess - # these signals are only delivered if/when you access the console? I - # don't really know what was going on there. From reading the - # GenerateConsoleCtrlEvent docs I don't know how it worked at all. - # - # I later spent a bunch of time trying to make GenerateConsoleCtrlEvent - # work for creating synthetic control-C events, and... failed - # utterly. There are lots of details in the code and comments - # removed/added at this commit: - # https://github.com/python-trio/trio/commit/95843654173e3e826c34d70a90b369ba6edf2c23 - # - # OTOH, if you pass os.kill any *other* signal number... then CPython - # just calls TerminateProcess (wtf). - # - # So, anyway, os.kill is not so useful for testing purposes. Instead, - # we use raise(): - # - # https://msdn.microsoft.com/en-us/library/dwwzkt4c.aspx - # - # Have to import cffi inside the 'if os.name' block because we don't - # depend on cffi on non-Windows platforms. (It would be easy to switch - # this to ctypes though if we ever remove the cffi dependency.) - # - # Some more information: - # https://bugs.python.org/issue26350 - # - # Anyway, we use this for two things: - # - redelivering unhandled signals - # - generating synthetic signals for tests - # and for both of those purposes, 'raise' works fine. - import cffi - - _ffi = cffi.FFI() - _ffi.cdef("int raise(int);") - _lib = _ffi.dlopen("api-ms-win-crt-runtime-l1-1-0.dll") - signal_raise = getattr(_lib, "raise") -else: - - def signal_raise(signum: int) -> None: - signal.pthread_kill(threading.get_ident(), signum) - - # See: #461 as to why this is needed. # The gist is that threading.main_thread() has the capability to lie to us # if somebody else edits the threading ident cache to replace the main From 785dc59309ca4f491562b817836092f54b7da4b1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 13 Nov 2024 06:34:38 +0000 Subject: [PATCH 49/52] [pre-commit.ci] pre-commit autoupdate (#3132) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/astral-sh/ruff-pre-commit: v0.7.2 → v0.7.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.2...v0.7.3) * Fix for ruff * More fixes * Flip if-statement * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: EXPLOSION --- .pre-commit-config.yaml | 2 +- src/trio/_core/_tests/test_run.py | 6 +++--- src/trio/_tests/type_tests/path.py | 15 ++++++--------- test-requirements.txt | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fe316fbf4..594f1d1b9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.2 + rev: v0.7.3 hooks: - id: ruff types: [file] diff --git a/src/trio/_core/_tests/test_run.py b/src/trio/_core/_tests/test_run.py index 7b3958804..f7ac155ba 100644 --- a/src/trio/_core/_tests/test_run.py +++ b/src/trio/_core/_tests/test_run.py @@ -2794,15 +2794,15 @@ async def spawn_tasks_in_old_nursery(task_status: _core.TaskStatus[None]) -> Non assert RaisesGroup(ValueError, ValueError).matches(excinfo.value.__cause__) -if sys.version_info <= (3, 11): +if sys.version_info >= (3, 11): def no_other_refs() -> list[object]: - return [sys._getframe(1)] + return [] else: def no_other_refs() -> list[object]: - return [] + return [sys._getframe(1)] @pytest.mark.skipif( diff --git a/src/trio/_tests/type_tests/path.py b/src/trio/_tests/type_tests/path.py index 6ea6717a6..27dbdd2a9 100644 --- a/src/trio/_tests/type_tests/path.py +++ b/src/trio/_tests/type_tests/path.py @@ -48,17 +48,15 @@ def sync_attrs(path: trio.Path) -> None: assert_type(path.as_posix(), str) assert_type(path.as_uri(), str) assert_type(path.is_absolute(), bool) - if sys.version_info > (3, 9): - assert_type(path.is_relative_to(path), bool) + assert_type(path.is_relative_to(path), bool) assert_type(path.is_reserved(), bool) assert_type(path.joinpath(path, "folder"), trio.Path) assert_type(path.match("*.py"), bool) assert_type(path.relative_to("/usr"), trio.Path) - if sys.version_info > (3, 12): + if sys.version_info >= (3, 12): assert_type(path.relative_to("/", walk_up=True), bool) assert_type(path.with_name("filename.txt"), trio.Path) - if sys.version_info > (3, 9): - assert_type(path.with_stem("readme"), trio.Path) + assert_type(path.with_stem("readme"), trio.Path) assert_type(path.with_suffix(".log"), trio.Path) @@ -75,7 +73,7 @@ async def async_attrs(path: trio.Path) -> None: assert_type(await path.group(), str) assert_type(await path.is_dir(), bool) assert_type(await path.is_file(), bool) - if sys.version_info > (3, 12): + if sys.version_info >= (3, 12): assert_type(await path.is_junction(), bool) if sys.platform != "win32": assert_type(await path.is_mount(), bool) @@ -95,8 +93,7 @@ async def async_attrs(path: trio.Path) -> None: assert_type(await path.owner(), str) assert_type(await path.read_bytes(), bytes) assert_type(await path.read_text(encoding="utf16", errors="replace"), str) - if sys.version_info > (3, 9): - assert_type(await path.readlink(), trio.Path) + assert_type(await path.readlink(), trio.Path) assert_type(await path.rename("another"), trio.Path) assert_type(await path.replace(path), trio.Path) assert_type(await path.resolve(), trio.Path) @@ -107,7 +104,7 @@ async def async_attrs(path: trio.Path) -> None: assert_type(await path.rmdir(), None) assert_type(await path.samefile("something_else"), bool) assert_type(await path.symlink_to("somewhere"), None) - if sys.version_info > (3, 10): + if sys.version_info >= (3, 10): assert_type(await path.hardlink_to("elsewhere"), None) assert_type(await path.touch(), None) assert_type(await path.unlink(missing_ok=True), None) diff --git a/test-requirements.txt b/test-requirements.txt index 9c0f87b82..158e04a53 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -113,7 +113,7 @@ pytest==8.3.3 # via -r test-requirements.in requests==2.32.3 # via sphinx -ruff==0.7.1 +ruff==0.7.3 # via -r test-requirements.in sniffio==1.3.1 # via -r test-requirements.in From 6995a38d2409b44703e8c3867d0b050351f08016 Mon Sep 17 00:00:00 2001 From: Jack Wilsdon Date: Sat, 16 Nov 2024 11:51:56 +0000 Subject: [PATCH 50/52] Don't create IPv6 socket if IPv6 is disabled --- src/trio/_tests/test_socket.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/trio/_tests/test_socket.py b/src/trio/_tests/test_socket.py index 3f68b285b..dc4bb467a 100644 --- a/src/trio/_tests/test_socket.py +++ b/src/trio/_tests/test_socket.py @@ -14,7 +14,7 @@ import pytest from .. import _core, socket as tsocket -from .._core._tests.tutil import binds_ipv6, creates_ipv6 +from .._core._tests.tutil import binds_ipv6, can_create_ipv6, creates_ipv6 from .._socket import _NUMERIC_ONLY, AddressFormat, SocketType, _SocketType, _try_sync from ..testing import assert_checkpoints, wait_all_tasks_blocked @@ -376,9 +376,12 @@ async def test_sniff_sockopts() -> None: from socket import AF_INET, AF_INET6, SOCK_DGRAM, SOCK_STREAM # generate the combinations of families/types we're testing: + families = [AF_INET] + if can_create_ipv6: + families.append(AF_INET6) sockets = [ stdlib_socket.socket(family, type_) - for family in [AF_INET, AF_INET6] + for family in families for type_ in [SOCK_DGRAM, SOCK_STREAM] ] for socket in sockets: From 0cdb3926691bf3405519ef00481a9e2a825c0021 Mon Sep 17 00:00:00 2001 From: A5rocks Date: Mon, 18 Nov 2024 13:27:05 +0900 Subject: [PATCH 51/52] Only run pypy w/ x64 --- .github/workflows/ci.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 10965e132..0747e6d35 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - python: ['pypy-3.10', '3.9', '3.10', '3.11', '3.12', '3.13'] + python: ['3.9', '3.10', '3.11', '3.12', '3.13'] arch: ['x86', 'x64'] lsp: [''] lsp_extract_file: [''] @@ -34,6 +34,11 @@ jobs: lsp: 'https://www.proxifier.com/download/legacy/ProxifierSetup342.exe' lsp_extract_file: '' extra_name: ', with IFS LSP' + - python: 'pypy-3.10' + arch: 'x64' + lsp: '' + lsp_extract_file: '' + extra_name: '' #- python: '3.9' # arch: 'x64' # lsp: 'http://download.pctools.com/mirror/updates/9.0.0.2308-SDavfree-lite_en.exe' From f724be58edaf1fd5b0671ba0da8292ff137c0656 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2024 04:18:22 +0000 Subject: [PATCH 52/52] [pre-commit.ci] pre-commit autoupdate (#3139) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/astral-sh/ruff-pre-commit: v0.7.3 → v0.7.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.3...v0.7.4) * Move None to end of type hint --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: EXPLOSION --- .pre-commit-config.yaml | 2 +- src/trio/_core/_run.py | 2 +- src/trio/testing/_fake_net.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 594f1d1b9..6f721cb58 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.3 + rev: v0.7.4 hooks: - id: ruff types: [file] diff --git a/src/trio/_core/_run.py b/src/trio/_core/_run.py index 21bdecd44..3d89ab404 100644 --- a/src/trio/_core/_run.py +++ b/src/trio/_core/_run.py @@ -1406,7 +1406,7 @@ class Task(metaclass=NoPublicConstructor): # type: ignore[misc] # Tasks start out unscheduled. # Explicit "Any" is not allowed _next_send_fn: Callable[[Any], object] | None = None # type: ignore[misc] - _next_send: Outcome[Any] | None | BaseException = None # type: ignore[misc] + _next_send: Outcome[Any] | BaseException | None = None # type: ignore[misc] _abort_func: Callable[[_core.RaiseCancelT], Abort] | None = None custom_sleep_data: Any = None # type: ignore[misc] diff --git a/src/trio/testing/_fake_net.py b/src/trio/testing/_fake_net.py index 6ec7f68b6..2f5bd624a 100644 --- a/src/trio/testing/_fake_net.py +++ b/src/trio/testing/_fake_net.py @@ -504,7 +504,7 @@ async def sendto( self, __data: Buffer, # noqa: PYI063 __flags: int, - __address: tuple[object, ...] | str | None | Buffer, + __address: tuple[object, ...] | str | Buffer | None, ) -> int: ... # Explicit "Any" is not allowed