From 99e53dca6c2cc6b36d24be10eaf5fa71b3c74406 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 2 Oct 2023 23:57:36 -0500 Subject: [PATCH 01/12] Enable flake8-bugbear rule --- notes-to-self/graceful-shutdown-idea.py | 2 +- .../how-does-windows-so-reuseaddr-work.py | 4 ++-- notes-to-self/socketpair-buffering.py | 9 +++++---- .../ssl-close-notify/ssl-close-notify.py | 2 +- notes-to-self/thread-closure-bug-demo.py | 4 +--- pyproject.toml | 8 ++++++-- trio/_abc.py | 11 ++++++++++- trio/_core/_generated_instrumentation.py | 4 ++-- trio/_core/_generated_io_epoll.py | 6 +++--- trio/_core/_generated_io_kqueue.py | 12 ++++++------ trio/_core/_generated_io_windows.py | 18 +++++++++--------- trio/_core/_generated_run.py | 16 ++++++++-------- trio/_core/_io_windows.py | 2 +- trio/_core/_local.py | 2 +- trio/_core/_run.py | 11 ++++++----- trio/_core/_tests/test_asyncgen.py | 2 +- trio/_core/_tests/test_guest_mode.py | 4 ++-- trio/_core/_tests/test_instrumentation.py | 2 +- trio/_core/_tests/test_multierror.py | 10 ++++++---- trio/_core/_tests/test_parking_lot.py | 2 +- trio/_core/_tests/test_run.py | 6 +++--- trio/_core/_wakeup_socketpair.py | 3 ++- trio/_dtls.py | 14 ++++++++------ trio/_highlevel_open_tcp_stream.py | 10 +++------- trio/_highlevel_socket.py | 2 +- trio/_socket.py | 2 +- trio/_ssl.py | 2 +- trio/_subprocess.py | 13 +++++++++---- trio/_tests/test_deprecate.py | 2 +- trio/_tests/test_dtls.py | 2 +- trio/_tests/test_exports.py | 8 ++++---- trio/_tests/test_file_io.py | 2 +- .../test_highlevel_open_tcp_listeners.py | 4 ++-- trio/_tests/test_highlevel_serve_listeners.py | 2 +- trio/_tests/test_path.py | 2 +- trio/_tests/test_socket.py | 12 ++++++++---- trio/_tests/test_ssl.py | 14 +++++++++----- trio/_tests/test_testing.py | 10 +++++----- trio/_tests/test_threads.py | 4 ++-- trio/_tests/test_tracing.py | 2 +- trio/_tests/type_tests/check_wraps.py | 3 +-- trio/_threads.py | 2 +- trio/_tools/gen_exports.py | 2 +- trio/socket.py | 2 +- trio/testing/_fake_net.py | 6 +++--- trio/testing/_memory_streams.py | 2 +- trio/testing/_sequencer.py | 4 +++- 47 files changed, 148 insertions(+), 120 deletions(-) diff --git a/notes-to-self/graceful-shutdown-idea.py b/notes-to-self/graceful-shutdown-idea.py index 76516b9f53..9497af9724 100644 --- a/notes-to-self/graceful-shutdown-idea.py +++ b/notes-to-self/graceful-shutdown-idea.py @@ -44,7 +44,7 @@ async def stream_handler(stream): # To trigger the shutdown: async def listen_for_shutdown_signals(): with trio.open_signal_receiver(signal.SIGINT, signal.SIGTERM) as signal_aiter: - async for sig in signal_aiter: + async for _sig in signal_aiter: gsm.start_shutdown() break # TODO: it'd be nice to have some logic like "if we get another 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 c6d356f072..c8cc04530e 100644 --- a/notes-to-self/how-does-windows-so-reuseaddr-work.py +++ b/notes-to-self/how-does-windows-so-reuseaddr-work.py @@ -26,7 +26,7 @@ def bind(sock, bind_type): elif bind_type == "specific": sock.bind(("127.0.0.1", 12345)) else: - assert False + raise AssertionError() def table_entry(mode1, bind_type1, mode2, bind_type2): @@ -53,7 +53,7 @@ def table_entry(mode1, bind_type1, mode2, bind_type2): ) print(""" """, end="") -for mode in modes: +for _mode in modes: print(" | " + " | ".join(["%8s" % bind_type for bind_type in bind_types]), end="") print( diff --git a/notes-to-self/socketpair-buffering.py b/notes-to-self/socketpair-buffering.py index 5e77a709b7..d53da72fc3 100644 --- a/notes-to-self/socketpair-buffering.py +++ b/notes-to-self/socketpair-buffering.py @@ -26,11 +26,12 @@ a.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, bufsize) b.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, bufsize) - try: - for i in range(10000000): + i = 0 + for i in range(10000000): # noqa: B007 # i unused inside loop + try: a.send(b"\x00") - except BlockingIOError: - pass + except BlockingIOError: + break print(f"setsockopt bufsize {bufsize}: {i}") a.close() 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 32ecbea2f0..7a55b8c99c 100644 --- a/notes-to-self/ssl-close-notify/ssl-close-notify.py +++ b/notes-to-self/ssl-close-notify/ssl-close-notify.py @@ -73,6 +73,6 @@ def server_thread_fn(): except ssl.SSLWantReadError: print("client got SSLWantReadError as expected") else: - assert False + raise AssertionError() client.close() client_done.set() diff --git a/notes-to-self/thread-closure-bug-demo.py b/notes-to-self/thread-closure-bug-demo.py index b09a87fe5f..b5da68c334 100644 --- a/notes-to-self/thread-closure-bug-demo.py +++ b/notes-to-self/thread-closure-bug-demo.py @@ -35,9 +35,7 @@ def traced_looper(): # Force w_locals to be instantiated (only matters on PyPy; on CPython # you can comment this line out and everything stays the same) print(locals()) - # Force x to be closed over (could use 'nonlocal' on py3) - if False: - x + nonlocal x # Force x to be closed over # Random nonsense whose only purpose is to trigger lots of calls to # the trace func count = 0 diff --git a/pyproject.toml b/pyproject.toml index 73b110ebac..484a20a3e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,10 +23,11 @@ src = ["trio", "notes-to-self"] select = [ "RUF", # Ruff-specific rules - "E", # Error "F", # pyflakes + "E", # Error + "W", # Warning "I", # isort - "YTT", # flake8-2020 + "B", # flake8-bugbear ] extend-ignore = [ 'F403', # undefined-local-with-import-star @@ -54,6 +55,9 @@ extend-exclude = [ [tool.ruff.isort] combine-as-imports = true +[tool.ruff.flake8-annotations] +ignore-fully-untyped = true + [tool.mypy] python_version = "3.8" diff --git a/trio/_abc.py b/trio/_abc.py index dbc7966cee..76b1fdfba4 100644 --- a/trio/_abc.py +++ b/trio/_abc.py @@ -80,9 +80,11 @@ class Instrument(metaclass=ABCMeta): def before_run(self) -> None: """Called at the beginning of :func:`trio.run`.""" + return def after_run(self) -> None: """Called just before :func:`trio.run` returns.""" + return def task_spawned(self, task: Task) -> None: """Called when the given task is created. @@ -91,6 +93,7 @@ def task_spawned(self, task: Task) -> None: task (trio.lowlevel.Task): The new task. """ + return def task_scheduled(self, task: Task) -> None: """Called when the given task becomes runnable. @@ -102,6 +105,7 @@ def task_scheduled(self, task: Task) -> None: task (trio.lowlevel.Task): The task that became runnable. """ + return def before_task_step(self, task: Task) -> None: """Called immediately before we resume running the given task. @@ -110,6 +114,7 @@ def before_task_step(self, task: Task) -> None: task (trio.lowlevel.Task): The task that is about to run. """ + return def after_task_step(self, task: Task) -> None: """Called when we return to the main run loop after a task has yielded. @@ -118,6 +123,7 @@ def after_task_step(self, task: Task) -> None: task (trio.lowlevel.Task): The task that just ran. """ + return def task_exited(self, task: Task) -> None: """Called when the given task exits. @@ -126,6 +132,7 @@ def task_exited(self, task: Task) -> None: task (trio.lowlevel.Task): The finished task. """ + return def before_io_wait(self, timeout: float) -> None: """Called before blocking to wait for I/O readiness. @@ -134,6 +141,7 @@ def before_io_wait(self, timeout: float) -> None: timeout (float): The number of seconds we are willing to wait. """ + return def after_io_wait(self, timeout: float) -> None: """Called after handling pending I/O. @@ -144,6 +152,7 @@ def after_io_wait(self, timeout: float) -> None: whether any I/O was ready. """ + return class HostnameResolver(metaclass=ABCMeta): @@ -679,7 +688,7 @@ async def __anext__(self) -> ReceiveType: try: return await self.receive() except trio.EndOfChannel: - raise StopAsyncIteration + raise StopAsyncIteration from None class Channel(SendChannel[T], ReceiveChannel[T]): diff --git a/trio/_core/_generated_instrumentation.py b/trio/_core/_generated_instrumentation.py index 652fed1288..c7fefc307a 100644 --- a/trio/_core/_generated_instrumentation.py +++ b/trio/_core/_generated_instrumentation.py @@ -21,7 +21,7 @@ def add_instrument(instrument: Instrument) -> None: try: return GLOBAL_RUN_CONTEXT.runner.instruments.add_instrument(instrument) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None def remove_instrument(instrument: Instrument) -> None: @@ -41,4 +41,4 @@ def remove_instrument(instrument: Instrument) -> None: try: return GLOBAL_RUN_CONTEXT.runner.instruments.remove_instrument(instrument) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None diff --git a/trio/_core/_generated_io_epoll.py b/trio/_core/_generated_io_epoll.py index 6df3950a6d..f80e988f38 100644 --- a/trio/_core/_generated_io_epoll.py +++ b/trio/_core/_generated_io_epoll.py @@ -20,7 +20,7 @@ async def wait_readable(fd: (int | _HasFileNo)) -> None: try: return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_readable(fd) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None async def wait_writable(fd: (int | _HasFileNo)) -> None: @@ -28,7 +28,7 @@ async def wait_writable(fd: (int | _HasFileNo)) -> None: try: return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_writable(fd) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None def notify_closing(fd: (int | _HasFileNo)) -> None: @@ -36,4 +36,4 @@ def notify_closing(fd: (int | _HasFileNo)) -> None: try: return GLOBAL_RUN_CONTEXT.runner.io_manager.notify_closing(fd) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None diff --git a/trio/_core/_generated_io_kqueue.py b/trio/_core/_generated_io_kqueue.py index 6367bc654d..b572831076 100644 --- a/trio/_core/_generated_io_kqueue.py +++ b/trio/_core/_generated_io_kqueue.py @@ -24,7 +24,7 @@ def current_kqueue() -> select.kqueue: try: return GLOBAL_RUN_CONTEXT.runner.io_manager.current_kqueue() except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None def monitor_kevent( @@ -34,7 +34,7 @@ def monitor_kevent( try: return GLOBAL_RUN_CONTEXT.runner.io_manager.monitor_kevent(ident, filter) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None async def wait_kevent( @@ -46,7 +46,7 @@ async def wait_kevent( ident, filter, abort_func ) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None async def wait_readable(fd: (int | _HasFileNo)) -> None: @@ -54,7 +54,7 @@ async def wait_readable(fd: (int | _HasFileNo)) -> None: try: return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_readable(fd) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None async def wait_writable(fd: (int | _HasFileNo)) -> None: @@ -62,7 +62,7 @@ async def wait_writable(fd: (int | _HasFileNo)) -> None: try: return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_writable(fd) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None def notify_closing(fd: (int | _HasFileNo)) -> None: @@ -70,4 +70,4 @@ def notify_closing(fd: (int | _HasFileNo)) -> None: try: return GLOBAL_RUN_CONTEXT.runner.io_manager.notify_closing(fd) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None diff --git a/trio/_core/_generated_io_windows.py b/trio/_core/_generated_io_windows.py index 4ed97a21db..e859829e2b 100644 --- a/trio/_core/_generated_io_windows.py +++ b/trio/_core/_generated_io_windows.py @@ -24,7 +24,7 @@ async def wait_readable(sock: (_HasFileNo | int)) -> None: try: return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_readable(sock) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None async def wait_writable(sock: (_HasFileNo | int)) -> None: @@ -32,7 +32,7 @@ async def wait_writable(sock: (_HasFileNo | int)) -> None: try: return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_writable(sock) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None def notify_closing(handle: (Handle | int | _HasFileNo)) -> None: @@ -40,7 +40,7 @@ def notify_closing(handle: (Handle | int | _HasFileNo)) -> None: try: return GLOBAL_RUN_CONTEXT.runner.io_manager.notify_closing(handle) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None def register_with_iocp(handle: (int | CData)) -> None: @@ -48,7 +48,7 @@ def register_with_iocp(handle: (int | CData)) -> None: try: return GLOBAL_RUN_CONTEXT.runner.io_manager.register_with_iocp(handle) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None async def wait_overlapped( @@ -60,7 +60,7 @@ async def wait_overlapped( handle_, lpOverlapped ) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None async def write_overlapped( @@ -72,7 +72,7 @@ async def write_overlapped( handle, data, file_offset ) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None async def readinto_overlapped( @@ -84,7 +84,7 @@ async def readinto_overlapped( handle, buffer, file_offset ) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None def current_iocp() -> int: @@ -92,7 +92,7 @@ def current_iocp() -> int: try: return GLOBAL_RUN_CONTEXT.runner.io_manager.current_iocp() except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None def monitor_completion_key() -> ContextManager[tuple[int, UnboundedQueue[object]]]: @@ -100,4 +100,4 @@ def monitor_completion_key() -> ContextManager[tuple[int, UnboundedQueue[object] try: return GLOBAL_RUN_CONTEXT.runner.io_manager.monitor_completion_key() except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None diff --git a/trio/_core/_generated_run.py b/trio/_core/_generated_run.py index 3e1b7b78f1..399e1dba85 100644 --- a/trio/_core/_generated_run.py +++ b/trio/_core/_generated_run.py @@ -42,7 +42,7 @@ def current_statistics() -> RunStatistics: try: return GLOBAL_RUN_CONTEXT.runner.current_statistics() except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None def current_time() -> float: @@ -59,7 +59,7 @@ def current_time() -> float: try: return GLOBAL_RUN_CONTEXT.runner.current_time() except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None def current_clock() -> Clock: @@ -68,7 +68,7 @@ def current_clock() -> Clock: try: return GLOBAL_RUN_CONTEXT.runner.current_clock() except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None def current_root_task() -> Task | None: @@ -81,7 +81,7 @@ def current_root_task() -> Task | None: try: return GLOBAL_RUN_CONTEXT.runner.current_root_task() except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None def reschedule(task: Task, next_send: Outcome[Any] = _NO_SEND) -> None: @@ -106,7 +106,7 @@ def reschedule(task: Task, next_send: Outcome[Any] = _NO_SEND) -> None: try: return GLOBAL_RUN_CONTEXT.runner.reschedule(task, next_send) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None def spawn_system_task( @@ -172,7 +172,7 @@ def spawn_system_task( async_fn, *args, name=name, context=context ) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None def current_trio_token() -> TrioToken: @@ -184,7 +184,7 @@ def current_trio_token() -> TrioToken: try: return GLOBAL_RUN_CONTEXT.runner.current_trio_token() except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None async def wait_all_tasks_blocked(cushion: float = 0.0) -> None: @@ -249,4 +249,4 @@ async def test_lock_fairness(): try: return await GLOBAL_RUN_CONTEXT.runner.wait_all_tasks_blocked(cushion) except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None diff --git a/trio/_core/_io_windows.py b/trio/_core/_io_windows.py index ba84525506..f1db1d9f1c 100644 --- a/trio/_core/_io_windows.py +++ b/trio/_core/_io_windows.py @@ -368,7 +368,7 @@ def _get_base_socket(sock: _HasFileNo | int | Handle) -> Handle: "https://github.com/python-trio/trio/issues/new, " "and include the output of running: " "netsh winsock show catalog" - ) + ) from ex # Otherwise we've gotten at least one layer deeper, so # loop back around to keep digging. sock = next_sock diff --git a/trio/_core/_local.py b/trio/_core/_local.py index 27252bc78d..3ddd7d9411 100644 --- a/trio/_core/_local.py +++ b/trio/_core/_local.py @@ -97,7 +97,7 @@ def reset(self, token: RunVarToken[T]) -> None: else: _run.GLOBAL_RUN_CONTEXT.runner._locals[self] = previous except AttributeError: - raise RuntimeError("Cannot be used outside of a run context") + raise RuntimeError("Cannot be used outside of a run context") from None token.redeemed = True diff --git a/trio/_core/_run.py b/trio/_core/_run.py index da9caf536c..801ef61ee1 100644 --- a/trio/_core/_run.py +++ b/trio/_core/_run.py @@ -115,7 +115,7 @@ def _count_context_run_tb_frames() -> int: def function_with_unique_name_xyzzy() -> NoReturn: try: - 1 / 0 + 1 / 0 # noqa: B018 # We need a ZeroDivisionError to fire except ZeroDivisionError: raise else: # pragma: no cover @@ -2358,7 +2358,7 @@ def my_done_callback(run_outcome): next_send = cast( EventResult, None ) # First iteration must be `None`, every iteration after that is EventResult - for tick in range(5): # expected need is 2 iterations + leave some wiggle room + for _tick in range(5): # expected need is 2 iterations + leave some wiggle room if runner.system_nursery is not None: # We're initialized enough to switch to async guest ticks break @@ -2367,7 +2367,7 @@ def my_done_callback(run_outcome): except StopIteration: # pragma: no cover raise TrioInternalError( "Guest runner exited before system nursery was initialized" - ) + ) from None if timeout != 0: # pragma: no cover guest_state.unrolled_run_gen.throw( TrioInternalError( @@ -2622,7 +2622,8 @@ def unrolled_run( RuntimeWarning( "Trio guest run got abandoned without properly finishing... " "weird stuff might happen" - ) + ), + stacklevel=1, ) except TrioInternalError: raise @@ -2745,7 +2746,7 @@ async def checkpoint_if_cancelled() -> None: task is task._runner.main_task and task._runner.ki_pending ): await _core.checkpoint() - assert False # pragma: no cover + raise AssertionError() # pragma: no cover task._cancel_points += 1 diff --git a/trio/_core/_tests/test_asyncgen.py b/trio/_core/_tests/test_asyncgen.py index bc7848df8e..1db3145826 100644 --- a/trio/_core/_tests/test_asyncgen.py +++ b/trio/_core/_tests/test_asyncgen.py @@ -226,7 +226,7 @@ async def async_main() -> None: # (if the run_sync_soon task runs before init on one tick and after init # on the next tick); if we try enough times, we can make the chance of # failure as small as we want. - for attempt in range(50): + for attempt in range(50): # noqa: B007 # used if failed needs_retry = False del record[:] del saved[:] diff --git a/trio/_core/_tests/test_guest_mode.py b/trio/_core/_tests/test_guest_mode.py index 80180be805..066bdc1e18 100644 --- a/trio/_core/_tests/test_guest_mode.py +++ b/trio/_core/_tests/test_guest_mode.py @@ -72,7 +72,7 @@ def done_callback(outcome): elif op == "unwrap": return obj.unwrap() else: # pragma: no cover - assert False + raise AssertionError() finally: # Make sure that exceptions raised here don't capture these, so that # if an exception does cause us to abandon a run then the Trio state @@ -301,7 +301,7 @@ async def sit_in_wait_all_tasks_blocked(watb_cscope): # wait_all_tasks_blocked should *not* return normally, but # only by cancellation. await trio.testing.wait_all_tasks_blocked(cushion=9999) - assert False # pragma: no cover + raise AssertionError() # pragma: no cover assert watb_cscope.cancelled_caught async def get_woken_by_host_deadline(watb_cscope): diff --git a/trio/_core/_tests/test_instrumentation.py b/trio/_core/_tests/test_instrumentation.py index 498a3eb272..9969e720e6 100644 --- a/trio/_core/_tests/test_instrumentation.py +++ b/trio/_core/_tests/test_instrumentation.py @@ -236,7 +236,7 @@ async def main(): def test_instrument_that_raises_on_getattr(): class EvilInstrument: def task_exited(self, task): - assert False # pragma: no cover + raise AssertionError() # pragma: no cover @property def after_run(self): diff --git a/trio/_core/_tests/test_multierror.py b/trio/_core/_tests/test_multierror.py index 6d9fd2a568..78b51b7cfb 100644 --- a/trio/_core/_tests/test_multierror.py +++ b/trio/_core/_tests/test_multierror.py @@ -376,7 +376,9 @@ def simple_filter(exc): return Exception() if isinstance(exc, KeyError): return RuntimeError() - assert False, "only ValueError and KeyError should exist" # pragma: no cover + raise AssertionError( + "only ValueError and KeyError should exist" + ) # pragma: no cover try: gc.set_debug(gc.DEBUG_SAVEALL) @@ -484,9 +486,9 @@ def test_pickle_multierror(protocol: int) -> None: my_except = ZeroDivisionError() try: - 1 / 0 - except ZeroDivisionError as e: - my_except = e + 1 / 0 # noqa: B018 # Need exception to fire + except ZeroDivisionError as exc: + my_except = exc # MultiError will collapse into different classes depending on the errors for cls, errors in ( diff --git a/trio/_core/_tests/test_parking_lot.py b/trio/_core/_tests/test_parking_lot.py index 3f03fdbade..244a712fd9 100644 --- a/trio/_core/_tests/test_parking_lot.py +++ b/trio/_core/_tests/test_parking_lot.py @@ -41,7 +41,7 @@ async def waiter(i, lot): nursery.start_soon(waiter, i, lot) await wait_all_tasks_blocked() assert len(record) == 3 - for i in range(3): + for _ in range(3): lot.unpark() await wait_all_tasks_blocked() # 1-by-1 wakeups are strict FIFO diff --git a/trio/_core/_tests/test_run.py b/trio/_core/_tests/test_run.py index f67f83a4b8..104b202558 100644 --- a/trio/_core/_tests/test_run.py +++ b/trio/_core/_tests/test_run.py @@ -469,7 +469,7 @@ async def crasher() -> NoReturn: # KeyError from crasher() assert type(exc) is KeyError else: # pragma: no cover - assert False + raise AssertionError() async def test_precancelled_task() -> None: @@ -829,7 +829,7 @@ async def test_timekeeping() -> None: if 1.0 <= accuracy < 2: # pragma: no branch break else: # pragma: no cover - assert False + raise AssertionError() async def test_failed_abort() -> None: @@ -963,7 +963,7 @@ async def crasher() -> None: try: await sleep_forever() except _core.Cancelled: - raise ValueError + raise ValueError from None async def cancelme() -> None: await sleep_forever() diff --git a/trio/_core/_wakeup_socketpair.py b/trio/_core/_wakeup_socketpair.py index 2ad1a023fe..ea63f81ab3 100644 --- a/trio/_core/_wakeup_socketpair.py +++ b/trio/_core/_wakeup_socketpair.py @@ -63,7 +63,8 @@ def wakeup_on_signals(self) -> None: "should set host_uses_signal_set_wakeup_fd=True. " "Otherwise, file a bug on Trio and we'll help you figure " "out what's going on." - ) + ), + stacklevel=1, ) def close(self) -> None: diff --git a/trio/_dtls.py b/trio/_dtls.py index d6baebafbc..5007ed7ab0 100644 --- a/trio/_dtls.py +++ b/trio/_dtls.py @@ -841,10 +841,7 @@ def __init__(self, endpoint: DTLSEndpoint, peer_address: Any, ctx: Context): # support and isn't useful anyway -- especially for DTLS where it's equivalent # to just performing a new handshake. ctx.set_options( - ( - SSL.OP_NO_QUERY_MTU - | SSL.OP_NO_RENEGOTIATION # type: ignore[attr-defined] - ) + SSL.OP_NO_QUERY_MTU | SSL.OP_NO_RENEGOTIATION # type: ignore[attr-defined] ) self._ssl = SSL.Connection(ctx) self._handshake_mtu = 0 @@ -1231,7 +1228,10 @@ def __del__(self) -> None: pass # Do this last, because it might raise an exception warnings.warn( - f"unclosed DTLS endpoint {self!r}", ResourceWarning, source=self + f"unclosed DTLS endpoint {self!r}", + ResourceWarning, + source=self, + stacklevel=1, ) def close(self) -> None: @@ -1305,7 +1305,9 @@ async def handler(dtls_channel): try: self.socket.getsockname() except OSError: - raise RuntimeError("DTLS socket must be bound before it can serve") + raise RuntimeError( + "DTLS socket must be bound before it can serve" + ) from None self._ensure_receive_loop() # We do cookie verification ourselves, so tell OpenSSL not to worry about it. # (See also _inject_client_hello_untrusted.) diff --git a/trio/_highlevel_open_tcp_stream.py b/trio/_highlevel_open_tcp_stream.py index 43c0ee2b45..87d6133d8c 100644 --- a/trio/_highlevel_open_tcp_stream.py +++ b/trio/_highlevel_open_tcp_stream.py @@ -280,9 +280,7 @@ async def open_tcp_stream( # getaddrinfo should have raised OSError instead of returning an empty # list. But let's be paranoid and handle it anyway: if not targets: - msg = "no results found for hostname lookup: {}".format( - format_host_port(host, port) - ) + msg = f"no results found for hostname lookup: {format_host_port(host, port)}" raise OSError(msg) reorder_for_rfc_6555_section_5_4(targets) @@ -357,7 +355,7 @@ async def attempt_connect( raise OSError( f"local_address={local_address!r} is incompatible " f"with remote address {sockaddr!r}" - ) + ) from None await sock.connect(sockaddr) @@ -402,9 +400,7 @@ async def attempt_connect( # nothing succeeded if winning_socket is None: assert len(oserrors) == len(targets) - msg = "all attempts to connect to {} failed".format( - format_host_port(host, port) - ) + msg = f"all attempts to connect to {format_host_port(host, port)} failed" raise OSError(msg) from ExceptionGroup(msg, oserrors) else: stream = trio.SocketStream(winning_socket) diff --git a/trio/_highlevel_socket.py b/trio/_highlevel_socket.py index 9ee8aa2249..cdde9db100 100644 --- a/trio/_highlevel_socket.py +++ b/trio/_highlevel_socket.py @@ -411,7 +411,7 @@ async def accept(self) -> SocketStream: sock, _ = await self.socket.accept() except OSError as exc: if exc.errno in _closed_stream_errnos: - raise trio.ClosedResourceError + raise trio.ClosedResourceError from None if exc.errno not in _ignorable_accept_errnos: raise else: diff --git a/trio/_socket.py b/trio/_socket.py index 540641a628..297c838ed1 100644 --- a/trio/_socket.py +++ b/trio/_socket.py @@ -464,7 +464,7 @@ async def _resolve_address_nocp( raise ValueError( "address should be a (host, port, [flowinfo, [scopeid]]) tuple" ) - elif family == getattr(_stdlib_socket, "AF_UNIX"): + elif hasattr(_stdlib_socket, "AF_UNIX") and family == _stdlib_socket.AF_UNIX: # unwrap path-likes assert isinstance(address, (str, bytes)) return os.fspath(address) diff --git a/trio/_ssl.py b/trio/_ssl.py index 21c4deabb3..d00a1fc487 100644 --- a/trio/_ssl.py +++ b/trio/_ssl.py @@ -433,7 +433,7 @@ def _check_status(self) -> None: elif self._state is _State.CLOSED: raise trio.ClosedResourceError else: # pragma: no cover - assert False + raise AssertionError() # This is probably the single trickiest function in Trio. It has lots of # comments, though, just make sure to think carefully if you ever have to diff --git a/trio/_subprocess.py b/trio/_subprocess.py index 94720b8562..9e93bb5919 100644 --- a/trio/_subprocess.py +++ b/trio/_subprocess.py @@ -385,7 +385,7 @@ async def _open_process( if options.get(key): raise TypeError( "trio.Process only supports communicating over " - "unbuffered byte streams; the '{}' option is not supported".format(key) + f"unbuffered byte streams; the '{key}' option is not supported" ) if os.name == "posix": @@ -452,7 +452,10 @@ async def _windows_deliver_cancel(p: Process) -> None: try: p.terminate() except OSError as exc: - warnings.warn(RuntimeWarning(f"TerminateProcess on {p!r} failed with: {exc!r}")) + warnings.warn( + RuntimeWarning(f"TerminateProcess on {p!r} failed with: {exc!r}"), + stacklevel=1, + ) async def _posix_deliver_cancel(p: Process) -> None: @@ -464,12 +467,14 @@ async def _posix_deliver_cancel(p: Process) -> None: f"process {p!r} ignored SIGTERM for 5 seconds. " "(Maybe you should pass a custom deliver_cancel?) " "Trying SIGKILL." - ) + ), + stacklevel=1, ) p.kill() except OSError as exc: warnings.warn( - RuntimeWarning(f"tried to kill process {p!r}, but failed with: {exc!r}") + RuntimeWarning(f"tried to kill process {p!r}, but failed with: {exc!r}"), + stacklevel=1, ) diff --git a/trio/_tests/test_deprecate.py b/trio/_tests/test_deprecate.py index da548fc715..96a5e28c6d 100644 --- a/trio/_tests/test_deprecate.py +++ b/trio/_tests/test_deprecate.py @@ -259,7 +259,7 @@ def test_module_with_deprecations(recwarn_always: pytest.WarningsRecorder) -> No assert "instead-string instead" in got.message.args[0] with pytest.raises(AttributeError): - module_with_deprecations.asdf # type: ignore[attr-defined] + module_with_deprecations.asdf # type: ignore[attr-defined] # noqa def test_tests_is_deprecated1() -> None: diff --git a/trio/_tests/test_dtls.py b/trio/_tests/test_dtls.py index a077451c4c..b103080f38 100644 --- a/trio/_tests/test_dtls.py +++ b/trio/_tests/test_dtls.py @@ -869,7 +869,7 @@ async def test_association_replaced_before_handshake_starts() -> None: # This test shouldn't send any packets def route_packet(packet: UDPPacket) -> NoReturn: # pragma: no cover - assert False + raise AssertionError() fn.route_packet = route_packet # type: ignore[assignment] # TODO add type annotations for FakeNet diff --git a/trio/_tests/test_exports.py b/trio/_tests/test_exports.py index c3d8a03b63..c155bc84e9 100644 --- a/trio/_tests/test_exports.py +++ b/trio/_tests/test_exports.py @@ -230,7 +230,7 @@ def no_underscores(symbols): static_names.update(ignored_missing_names) else: # pragma: no cover - assert False + raise AssertionError() # remove py.typed file if tool in ("mypy", "pyright_verifytypes") and not py_typed_exists: @@ -256,7 +256,7 @@ def no_underscores(symbols): print() for name in sorted(missing_names): print(f" {name}") - assert False + raise AssertionError() # this could be sped up by only invoking mypy once per module, or even once for all @@ -413,7 +413,7 @@ def lookup_symbol(symbol): static_names -= ignore_names else: # pragma: no cover - assert False, "unknown tool" + raise AssertionError("unknown tool") missing = runtime_names - static_names extra = static_names - runtime_names @@ -523,7 +523,7 @@ def test_nopublic_is_final() -> None: assert class_is_final(_util.NoPublicConstructor) # This is itself final. for module in ALL_MODULES: - for name, class_ in module.__dict__.items(): + for _name, class_ in module.__dict__.items(): if isinstance(class_, _util.NoPublicConstructor): assert class_is_final(class_) diff --git a/trio/_tests/test_file_io.py b/trio/_tests/test_file_io.py index bae426cf48..11faccbfaa 100644 --- a/trio/_tests/test_file_io.py +++ b/trio/_tests/test_file_io.py @@ -78,7 +78,7 @@ def unsupported_attr(self): # pragma: no cover assert hasattr(async_file.wrapped, "unsupported_attr") with pytest.raises(AttributeError): - getattr(async_file, "unsupported_attr") + async_file.unsupported_attr # noqa: B018 def test_type_stubs_match_lists() -> None: diff --git a/trio/_tests/test_highlevel_open_tcp_listeners.py b/trio/_tests/test_highlevel_open_tcp_listeners.py index 2c190debc0..f06afdaaa0 100644 --- a/trio/_tests/test_highlevel_open_tcp_listeners.py +++ b/trio/_tests/test_highlevel_open_tcp_listeners.py @@ -156,7 +156,7 @@ def getsockopt( ) -> int | bytes: if (level, optname) == (tsocket.SOL_SOCKET, tsocket.SO_ACCEPTCONN): return True - assert False # pragma: no cover + raise AssertionError() # pragma: no cover @overload def setsockopt(self, /, level: int, optname: int, value: int | Buffer) -> None: @@ -292,7 +292,7 @@ async def handler(stream: SendStream) -> None: listeners: list[SocketListener] = await nursery.start(serve_tcp, handler, 0) stream = await open_stream_to_socket_listener(listeners[0]) async with stream: - await stream.receive_some(1) == b"x" + assert await stream.receive_some(1) == b"x" nursery.cancel_scope.cancel() diff --git a/trio/_tests/test_highlevel_serve_listeners.py b/trio/_tests/test_highlevel_serve_listeners.py index 65804f4222..a315dd09ea 100644 --- a/trio/_tests/test_highlevel_serve_listeners.py +++ b/trio/_tests/test_highlevel_serve_listeners.py @@ -87,7 +87,7 @@ async def test_serve_listeners_accept_unrecognized_error(): listener = MemoryListener() async def raise_error(): - raise error + raise error # noqa: B023 # Set from loop listener.accept_hook = raise_error diff --git a/trio/_tests/test_path.py b/trio/_tests/test_path.py index bfef1aaf2c..b2df7fe91c 100644 --- a/trio/_tests/test_path.py +++ b/trio/_tests/test_path.py @@ -114,7 +114,7 @@ async def test_compare_async_stat_methods(method_name): async def test_invalid_name_not_wrapped(path): with pytest.raises(AttributeError): - getattr(path, "invalid_fake_attr") + path.invalid_fake_attr # noqa: B018 @pytest.mark.parametrize("method_name", ["absolute", "resolve"]) diff --git a/trio/_tests/test_socket.py b/trio/_tests/test_socket.py index 40ffefb8cd..ed7079b277 100644 --- a/trio/_tests/test_socket.py +++ b/trio/_tests/test_socket.py @@ -387,7 +387,7 @@ async def test_SocketType_basics() -> None: # our __getattr__ handles unknown names with pytest.raises(AttributeError): - sock.asdf # type: ignore[attr-defined] + sock.asdf # type: ignore[attr-defined] # noqa: B018 # type family proto stdlib_sock = stdlib_socket.socket() @@ -586,7 +586,10 @@ async def res( | tuple[str, str, int] | tuple[str, str, int, int] ) -> Any: - return await sock._resolve_address_nocp(args, local=local) + return await sock._resolve_address_nocp( + args, + local=local, # noqa: B023 # local is not bound in function definition + ) assert_eq(await res((addrs.arbitrary, "http")), (addrs.arbitrary, 80)) if v6: @@ -691,7 +694,7 @@ async def test_SocketType_non_blocking_paths() -> None: # immediate success (also checks that the previous attempt didn't # actually read anything) with assert_checkpoints(): - await ta.recv(10) == b"1" + assert await ta.recv(10) == b"1" # immediate failure with assert_checkpoints(): with pytest.raises(TypeError): @@ -1108,7 +1111,8 @@ async def receiver() -> None: async def test_many_sockets() -> None: total = 5000 # Must be more than MAX_AFD_GROUP_SIZE sockets = [] - for x in range(total // 2): + x = 0 + for x in range(total // 2): # noqa: B007 # Used for check below try: a, b = stdlib_socket.socketpair() except OSError as e: # pragma: no cover diff --git a/trio/_tests/test_ssl.py b/trio/_tests/test_ssl.py index d92e35b0d9..abcdeca939 100644 --- a/trio/_tests/test_ssl.py +++ b/trio/_tests/test_ssl.py @@ -84,7 +84,7 @@ def client_ctx(request): ctx.maximum_version = ssl.TLSVersion.TLSv1_2 return ctx else: # pragma: no cover - assert False + raise AssertionError() # The blocking socket server. @@ -367,9 +367,13 @@ def ssl_wrap_pair( client_transport, server_transport, *, - client_kwargs={}, - server_kwargs={}, + client_kwargs=None, + server_kwargs=None, ): + if server_kwargs is None: + server_kwargs = {} + if client_kwargs is None: + client_kwargs = {} client_ssl = SSLStream( client_transport, client_ctx, @@ -464,7 +468,7 @@ async def test_attributes(client_ctx): assert s.server_side == False # noqa assert s.server_hostname == "trio-test-1.example.org" with pytest.raises(AttributeError): - s.asfdasdfsa + s.asfdasdfsa # noqa: B018 # __dir__ assert "transport_stream" in dir(s) @@ -914,7 +918,7 @@ async def server_closer(): # And once the connection is has been closed *locally*, then instead of # getting empty bytestrings we get a proper error with pytest.raises(ClosedResourceError): - await client_ssl.receive_some(10) == b"" + assert await client_ssl.receive_some(10) == b"" with pytest.raises(ClosedResourceError): await client_ssl.unwrap() diff --git a/trio/_tests/test_testing.py b/trio/_tests/test_testing.py index 3b5a57d3ec..53623cdc4e 100644 --- a/trio/_tests/test_testing.py +++ b/trio/_tests/test_testing.py @@ -110,7 +110,7 @@ async def test_assert_checkpoints(recwarn): with pytest.raises(AssertionError): with assert_checkpoints(): - 1 + 1 + 1 + 1 # noqa: B018 # partial yield cases # if you have a schedule point but not a cancel point, or vice-versa, then @@ -132,7 +132,7 @@ async def test_assert_checkpoints(recwarn): async def test_assert_no_checkpoints(recwarn): with assert_no_checkpoints(): - 1 + 1 + 1 + 1 # noqa: B018 with pytest.raises(AssertionError): with assert_no_checkpoints(): @@ -233,11 +233,11 @@ async def child(i): async def test__assert_raises(): with pytest.raises(AssertionError): with _assert_raises(RuntimeError): - 1 + 1 + 1 + 1 # noqa: B018 with pytest.raises(TypeError): with _assert_raises(RuntimeError): - "foo" + 1 + "foo" + 1 # noqa: B018 with _assert_raises(RuntimeError): raise RuntimeError @@ -622,7 +622,7 @@ async def check(listener): server_stream = await listener.accept() async with server_stream: await client_stream.send_all(b"x") - await server_stream.receive_some(1) == b"x" + assert await server_stream.receive_some(1) == b"x" # Listener bound to localhost sock = tsocket.socket() diff --git a/trio/_tests/test_threads.py b/trio/_tests/test_threads.py index 9e448a4d38..5b638d0c01 100644 --- a/trio/_tests/test_threads.py +++ b/trio/_tests/test_threads.py @@ -463,7 +463,7 @@ async def run_thread(event): async with _core.open_nursery() as nursery: print("spawning") events = [] - for i in range(COUNT): + for _i in range(COUNT): events.append(Event()) nursery.start_soon(run_thread, events[-1]) await wait_all_tasks_blocked() @@ -798,7 +798,7 @@ def test_run_fn_as_system_task_catched_badly_typed_token(): async def test_from_thread_inside_trio_thread(): def not_called(): # pragma: no cover - assert False + raise AssertionError() trio_token = _core.current_trio_token() with pytest.raises(RuntimeError): diff --git a/trio/_tests/test_tracing.py b/trio/_tests/test_tracing.py index e5110eaff3..796a92c2a1 100644 --- a/trio/_tests/test_tracing.py +++ b/trio/_tests/test_tracing.py @@ -21,7 +21,7 @@ async def coro2_async_gen(event): async def coro3_async_gen(event: trio.Event) -> None: - async for x in coro2_async_gen(event): + async for _x in coro2_async_gen(event): pass diff --git a/trio/_tests/type_tests/check_wraps.py b/trio/_tests/type_tests/check_wraps.py index 456aa3dffb..5692738be4 100644 --- a/trio/_tests/type_tests/check_wraps.py +++ b/trio/_tests/type_tests/check_wraps.py @@ -1,8 +1,7 @@ # https://github.com/python-trio/trio/issues/2775#issuecomment-1702267589 # (except platform independent...) -import typing_extensions - import trio +import typing_extensions async def fn(s: trio.SocketStream) -> None: diff --git a/trio/_threads.py b/trio/_threads.py index 24905cfbde..f93e4263ec 100644 --- a/trio/_threads.py +++ b/trio/_threads.py @@ -282,7 +282,7 @@ def _run_fn_as_system_task( except AttributeError: raise RuntimeError( "this thread wasn't created by Trio, pass kwarg trio_token=..." - ) + ) from None # Avoid deadlock by making sure we're not called from Trio thread try: diff --git a/trio/_tools/gen_exports.py b/trio/_tools/gen_exports.py index 153070bfc9..fafd3c0a3d 100755 --- a/trio/_tools/gen_exports.py +++ b/trio/_tools/gen_exports.py @@ -39,7 +39,7 @@ try: return{}GLOBAL_RUN_CONTEXT.{}.{} except AttributeError: - raise RuntimeError("must be called from async context") + raise RuntimeError("must be called from async context") from None """ diff --git a/trio/socket.py b/trio/socket.py index a9e276c782..ec8c97c69e 100644 --- a/trio/socket.py +++ b/trio/socket.py @@ -83,7 +83,7 @@ IP_BIND_ADDRESS_NO_PORT: int else: try: - IP_BIND_ADDRESS_NO_PORT + IP_BIND_ADDRESS_NO_PORT # noqa: B018 # "useless expression" except NameError: if sys.platform == "linux": IP_BIND_ADDRESS_NO_PORT = 24 diff --git a/trio/testing/_fake_net.py b/trio/testing/_fake_net.py index 74ce32d37f..9dc0f1ee9a 100644 --- a/trio/testing/_fake_net.py +++ b/trio/testing/_fake_net.py @@ -33,7 +33,7 @@ def _family_for(ip: IPAddress) -> int: return trio.socket.AF_INET elif isinstance(ip, ipaddress.IPv6Address): return trio.socket.AF_INET6 - assert False # pragma: no cover + raise AssertionError() # pragma: no cover def _wildcard_ip_for(family: int) -> IPAddress: @@ -42,7 +42,7 @@ def _wildcard_ip_for(family: int) -> IPAddress: elif family == trio.socket.AF_INET6: return ipaddress.ip_address("::") else: - assert False + raise AssertionError() def _localhost_ip_for(family: int) -> IPAddress: @@ -51,7 +51,7 @@ def _localhost_ip_for(family: int) -> IPAddress: elif family == trio.socket.AF_INET6: return ipaddress.ip_address("::1") else: - assert False + raise AssertionError() def _fake_err(code): diff --git a/trio/testing/_memory_streams.py b/trio/testing/_memory_streams.py index 2a9bc1a2fd..04098c8c60 100644 --- a/trio/testing/_memory_streams.py +++ b/trio/testing/_memory_streams.py @@ -313,7 +313,7 @@ def memory_stream_pump( else: memory_receive_stream.put_data(data) except _core.ClosedResourceError: - raise _core.BrokenResourceError("MemoryReceiveStream was closed") + raise _core.BrokenResourceError("MemoryReceiveStream was closed") from None return True diff --git a/trio/testing/_sequencer.py b/trio/testing/_sequencer.py index a6e6d8e8eb..4ae3e54764 100644 --- a/trio/testing/_sequencer.py +++ b/trio/testing/_sequencer.py @@ -74,7 +74,9 @@ async def __call__(self, position: int) -> AsyncIterator[None]: self._broken = True for event in self._sequence_points.values(): event.set() - raise RuntimeError("Sequencer wait cancelled -- sequence broken") + raise RuntimeError( + "Sequencer wait cancelled -- sequence broken" + ) from None else: if self._broken: raise RuntimeError("sequence broken!") From 3ac6437782b71656a768f4be88891a2067ab09ac Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Tue, 3 Oct 2023 00:21:02 -0500 Subject: [PATCH 02/12] Revert accidentally disabling flake8-2020 --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 484a20a3e0..792588d95c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,7 @@ select = [ "W", # Warning "I", # isort "B", # flake8-bugbear + "YTT", # flake8-2020 ] extend-ignore = [ 'F403', # undefined-local-with-import-star From 97bcb65405b969d8b4c6905ffe0c4e452092774d Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 11 Oct 2023 19:48:42 -0500 Subject: [PATCH 03/12] Remove unrelated setting change --- pyproject.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 792588d95c..12583c5c1e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,9 +56,6 @@ extend-exclude = [ [tool.ruff.isort] combine-as-imports = true -[tool.ruff.flake8-annotations] -ignore-fully-untyped = true - [tool.mypy] python_version = "3.8" From 11479806a721b0e27e6d4099eab91f59db247976 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 11 Oct 2023 20:28:59 -0500 Subject: [PATCH 04/12] Suggestions from code review --- notes-to-self/how-does-windows-so-reuseaddr-work.py | 2 +- notes-to-self/socketpair-buffering.py | 11 +++++------ trio/_core/_tests/test_asyncgen.py | 4 ++-- trio/_tests/test_deprecate.py | 2 +- trio/_tests/test_socket.py | 7 +++---- trio/_tests/test_threads.py | 2 +- trio/_tests/test_tracing.py | 2 +- 7 files changed, 14 insertions(+), 16 deletions(-) diff --git a/notes-to-self/how-does-windows-so-reuseaddr-work.py b/notes-to-self/how-does-windows-so-reuseaddr-work.py index c8cc04530e..70dd75e39f 100644 --- a/notes-to-self/how-does-windows-so-reuseaddr-work.py +++ b/notes-to-self/how-does-windows-so-reuseaddr-work.py @@ -53,7 +53,7 @@ def table_entry(mode1, bind_type1, mode2, bind_type2): ) print(""" """, end="") -for _mode in modes: +for _ in modes: print(" | " + " | ".join(["%8s" % bind_type for bind_type in bind_types]), end="") print( diff --git a/notes-to-self/socketpair-buffering.py b/notes-to-self/socketpair-buffering.py index d53da72fc3..e6169c25d3 100644 --- a/notes-to-self/socketpair-buffering.py +++ b/notes-to-self/socketpair-buffering.py @@ -26,13 +26,12 @@ a.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, bufsize) b.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, bufsize) - i = 0 - for i in range(10000000): # noqa: B007 # i unused inside loop - try: + try: + for _count in range(10000000): a.send(b"\x00") - except BlockingIOError: - break + except BlockingIOError: + break - print(f"setsockopt bufsize {bufsize}: {i}") + print(f"setsockopt bufsize {bufsize}: {_count}") a.close() b.close() diff --git a/trio/_core/_tests/test_asyncgen.py b/trio/_core/_tests/test_asyncgen.py index 1db3145826..2fe9a75b77 100644 --- a/trio/_core/_tests/test_asyncgen.py +++ b/trio/_core/_tests/test_asyncgen.py @@ -226,7 +226,7 @@ async def async_main() -> None: # (if the run_sync_soon task runs before init on one tick and after init # on the next tick); if we try enough times, we can make the chance of # failure as small as we want. - for attempt in range(50): # noqa: B007 # used if failed + for _attempt in range(50): needs_retry = False del record[:] del saved[:] @@ -240,7 +240,7 @@ async def async_main() -> None: else: # pragma: no cover pytest.fail( "Didn't manage to hit the trailing_finalizer_asyncgens case " - f"despite trying {attempt} times" + f"despite trying {_attempt} times" ) diff --git a/trio/_tests/test_deprecate.py b/trio/_tests/test_deprecate.py index 96a5e28c6d..91bcc65c4c 100644 --- a/trio/_tests/test_deprecate.py +++ b/trio/_tests/test_deprecate.py @@ -259,7 +259,7 @@ def test_module_with_deprecations(recwarn_always: pytest.WarningsRecorder) -> No assert "instead-string instead" in got.message.args[0] with pytest.raises(AttributeError): - module_with_deprecations.asdf # type: ignore[attr-defined] # noqa + module_with_deprecations.asdf # type: ignore[attr-defined] # noqa: B018 def test_tests_is_deprecated1() -> None: diff --git a/trio/_tests/test_socket.py b/trio/_tests/test_socket.py index ed7079b277..b6e0e101d3 100644 --- a/trio/_tests/test_socket.py +++ b/trio/_tests/test_socket.py @@ -1111,8 +1111,7 @@ async def receiver() -> None: async def test_many_sockets() -> None: total = 5000 # Must be more than MAX_AFD_GROUP_SIZE sockets = [] - x = 0 - for x in range(total // 2): # noqa: B007 # Used for check below + for _x in range(total // 2): try: a, b = stdlib_socket.socketpair() except OSError as e: # pragma: no cover @@ -1126,5 +1125,5 @@ async def test_many_sockets() -> None: nursery.cancel_scope.cancel() for sock in sockets: sock.close() - if x != total // 2 - 1: # pragma: no cover - print(f"Unable to open more than {(x-1)*2} sockets.") + if _x != total // 2 - 1: # pragma: no cover + print(f"Unable to open more than {(_x-1)*2} sockets.") diff --git a/trio/_tests/test_threads.py b/trio/_tests/test_threads.py index 5b638d0c01..ab36402b0a 100644 --- a/trio/_tests/test_threads.py +++ b/trio/_tests/test_threads.py @@ -463,7 +463,7 @@ async def run_thread(event): async with _core.open_nursery() as nursery: print("spawning") events = [] - for _i in range(COUNT): + for _ in range(COUNT): events.append(Event()) nursery.start_soon(run_thread, events[-1]) await wait_all_tasks_blocked() diff --git a/trio/_tests/test_tracing.py b/trio/_tests/test_tracing.py index 796a92c2a1..f067bb9d32 100644 --- a/trio/_tests/test_tracing.py +++ b/trio/_tests/test_tracing.py @@ -21,7 +21,7 @@ async def coro2_async_gen(event): async def coro3_async_gen(event: trio.Event) -> None: - async for _x in coro2_async_gen(event): + async for _ in coro2_async_gen(event): pass From 4213618946b2e4775ec46d1b6af25a2dd597c595 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 11 Oct 2023 20:39:06 -0500 Subject: [PATCH 05/12] Explain "useless expression" errors All but the one in `trio/_tests/test_socket.py` line 390 because it already has a lot of comments --- trio/_tests/test_file_io.py | 2 +- trio/_tests/test_path.py | 2 +- trio/_tests/test_ssl.py | 2 +- trio/_tests/test_testing.py | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/trio/_tests/test_file_io.py b/trio/_tests/test_file_io.py index 11faccbfaa..0e554088da 100644 --- a/trio/_tests/test_file_io.py +++ b/trio/_tests/test_file_io.py @@ -78,7 +78,7 @@ def unsupported_attr(self): # pragma: no cover assert hasattr(async_file.wrapped, "unsupported_attr") with pytest.raises(AttributeError): - async_file.unsupported_attr # noqa: B018 + async_file.unsupported_attr # noqa: B018 # "useless expression" def test_type_stubs_match_lists() -> None: diff --git a/trio/_tests/test_path.py b/trio/_tests/test_path.py index b2df7fe91c..b1ebc98d10 100644 --- a/trio/_tests/test_path.py +++ b/trio/_tests/test_path.py @@ -114,7 +114,7 @@ async def test_compare_async_stat_methods(method_name): async def test_invalid_name_not_wrapped(path): with pytest.raises(AttributeError): - path.invalid_fake_attr # noqa: B018 + path.invalid_fake_attr # noqa: B018 # "useless expression" @pytest.mark.parametrize("method_name", ["absolute", "resolve"]) diff --git a/trio/_tests/test_ssl.py b/trio/_tests/test_ssl.py index abcdeca939..2d0c10aea6 100644 --- a/trio/_tests/test_ssl.py +++ b/trio/_tests/test_ssl.py @@ -468,7 +468,7 @@ async def test_attributes(client_ctx): assert s.server_side == False # noqa assert s.server_hostname == "trio-test-1.example.org" with pytest.raises(AttributeError): - s.asfdasdfsa # noqa: B018 + s.asfdasdfsa # noqa: B018 # "useless expression" # __dir__ assert "transport_stream" in dir(s) diff --git a/trio/_tests/test_testing.py b/trio/_tests/test_testing.py index 846167c638..ea5ab2ab6a 100644 --- a/trio/_tests/test_testing.py +++ b/trio/_tests/test_testing.py @@ -110,7 +110,7 @@ async def test_assert_checkpoints(recwarn): with pytest.raises(AssertionError): with assert_checkpoints(): - 1 + 1 # noqa: B018 + 1 + 1 # noqa: B018 # "useless expression" # partial yield cases # if you have a schedule point but not a cancel point, or vice-versa, then @@ -132,7 +132,7 @@ async def test_assert_checkpoints(recwarn): async def test_assert_no_checkpoints(recwarn): with assert_no_checkpoints(): - 1 + 1 # noqa: B018 + 1 + 1 # noqa: B018 # "useless expression" with pytest.raises(AssertionError): with assert_no_checkpoints(): @@ -233,11 +233,11 @@ async def child(i): async def test__assert_raises(): with pytest.raises(AssertionError): with _assert_raises(RuntimeError): - 1 + 1 # noqa: B018 + 1 + 1 # noqa: B018 # "useless expression" with pytest.raises(TypeError): with _assert_raises(RuntimeError): - "foo" + 1 # noqa: B018 + "foo" + 1 # noqa: B018 # "useless expression" with _assert_raises(RuntimeError): raise RuntimeError From 9043b483a80819c40ffa2dbca45258799197d224 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 11 Oct 2023 20:58:30 -0500 Subject: [PATCH 06/12] Test that do-nothing implementations of hooks exist --- trio/_tests/test_abc.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/trio/_tests/test_abc.py b/trio/_tests/test_abc.py index b93c48f539..4b0ff1bc99 100644 --- a/trio/_tests/test_abc.py +++ b/trio/_tests/test_abc.py @@ -4,6 +4,32 @@ import pytest from .. import abc as tabc +from ..lowlevel import Task + + +def test_instrument_implements_hook_methods() -> None: + attrs = { + "before_run": (), + "after_run": (), + "task_spawned": (Task,), + "task_scheduled": (Task,), + "before_task_step": (Task,), + "after_task_step": (Task,), + "task_exited": (Task,), + "before_io_wait": (3.3,), + "after_io_wait": (3.3,), + } + + mayonnaise = tabc.Instrument() + + for method_name, args in attrs.items(): + assert hasattr(mayonnaise, method_name) + method = getattr(mayonnaise, method_name) + assert callable(method) + try: + method(*args) + except Exception as exc: + raise AssertionError("Raised exception") from exc async def test_AsyncResource_defaults() -> None: From 2bd476d98b99c34c16a6c18bf8e3e83685a4fddf Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Wed, 11 Oct 2023 21:09:59 -0500 Subject: [PATCH 07/12] Make test use `getattr` again and ignore constant getattr warning --- trio/_tests/test_path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trio/_tests/test_path.py b/trio/_tests/test_path.py index b1ebc98d10..480310242a 100644 --- a/trio/_tests/test_path.py +++ b/trio/_tests/test_path.py @@ -114,7 +114,7 @@ async def test_compare_async_stat_methods(method_name): async def test_invalid_name_not_wrapped(path): with pytest.raises(AttributeError): - path.invalid_fake_attr # noqa: B018 # "useless expression" + getattr(path, "invalid_fake_attr") # noqa: B009 # "get-attr-with-constant" @pytest.mark.parametrize("method_name", ["absolute", "resolve"]) From f9c18dc3639be1bd69508831e0e7d3134330bd7a Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Thu, 12 Oct 2023 17:36:27 -0500 Subject: [PATCH 08/12] Do not re-raise exception, will cause test failure regargless --- trio/_tests/test_abc.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/trio/_tests/test_abc.py b/trio/_tests/test_abc.py index 4b0ff1bc99..e5e8260f9c 100644 --- a/trio/_tests/test_abc.py +++ b/trio/_tests/test_abc.py @@ -26,10 +26,7 @@ def test_instrument_implements_hook_methods() -> None: assert hasattr(mayonnaise, method_name) method = getattr(mayonnaise, method_name) assert callable(method) - try: - method(*args) - except Exception as exc: - raise AssertionError("Raised exception") from exc + method(*args) async def test_AsyncResource_defaults() -> None: From a5afed75414bb5229c7ac1c3d168744ffb4b8802 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 16 Oct 2023 17:05:01 -0500 Subject: [PATCH 09/12] Suggestions from code review --- trio/_core/_run.py | 2 +- trio/_core/_tests/test_guest_mode.py | 7 +++++-- trio/_core/_tests/test_instrumentation.py | 2 +- trio/_core/_tests/test_multierror.py | 2 +- trio/_dtls.py | 3 ++- trio/_tests/test_deprecate.py | 2 +- trio/testing/_fake_net.py | 10 +++++----- 7 files changed, 16 insertions(+), 12 deletions(-) diff --git a/trio/_core/_run.py b/trio/_core/_run.py index 801ef61ee1..9a15d5c904 100644 --- a/trio/_core/_run.py +++ b/trio/_core/_run.py @@ -2746,7 +2746,7 @@ async def checkpoint_if_cancelled() -> None: task is task._runner.main_task and task._runner.ki_pending ): await _core.checkpoint() - raise AssertionError() # pragma: no cover + raise AssertionError("this should never happen") # pragma: no cover task._cancel_points += 1 diff --git a/trio/_core/_tests/test_guest_mode.py b/trio/_core/_tests/test_guest_mode.py index 066bdc1e18..5186eccd82 100644 --- a/trio/_core/_tests/test_guest_mode.py +++ b/trio/_core/_tests/test_guest_mode.py @@ -72,7 +72,7 @@ def done_callback(outcome): elif op == "unwrap": return obj.unwrap() else: # pragma: no cover - raise AssertionError() + raise NotImplementedError(f"{op!r} not handled") finally: # Make sure that exceptions raised here don't capture these, so that # if an exception does cause us to abandon a run then the Trio state @@ -301,7 +301,10 @@ async def sit_in_wait_all_tasks_blocked(watb_cscope): # wait_all_tasks_blocked should *not* return normally, but # only by cancellation. await trio.testing.wait_all_tasks_blocked(cushion=9999) - raise AssertionError() # pragma: no cover + raise AssertionError( # pragma: no cover + "wait_all_tasks_blocked should *not* return normally, " + "only by cancellation." + ) assert watb_cscope.cancelled_caught async def get_woken_by_host_deadline(watb_cscope): diff --git a/trio/_core/_tests/test_instrumentation.py b/trio/_core/_tests/test_instrumentation.py index 9969e720e6..b92a976ada 100644 --- a/trio/_core/_tests/test_instrumentation.py +++ b/trio/_core/_tests/test_instrumentation.py @@ -236,7 +236,7 @@ async def main(): def test_instrument_that_raises_on_getattr(): class EvilInstrument: def task_exited(self, task): - raise AssertionError() # pragma: no cover + raise AssertionError("this should never happen") # pragma: no cover @property def after_run(self): diff --git a/trio/_core/_tests/test_multierror.py b/trio/_core/_tests/test_multierror.py index 78b51b7cfb..c5cc709d5e 100644 --- a/trio/_core/_tests/test_multierror.py +++ b/trio/_core/_tests/test_multierror.py @@ -486,7 +486,7 @@ def test_pickle_multierror(protocol: int) -> None: my_except = ZeroDivisionError() try: - 1 / 0 # noqa: B018 # Need exception to fire + 1 / 0 # noqa: B018 # "useless statement" except ZeroDivisionError as exc: my_except = exc diff --git a/trio/_dtls.py b/trio/_dtls.py index 5007ed7ab0..cc7756cee3 100644 --- a/trio/_dtls.py +++ b/trio/_dtls.py @@ -1305,7 +1305,8 @@ async def handler(dtls_channel): try: self.socket.getsockname() except OSError: - raise RuntimeError( + # TODO: Write test that makes triggers this + raise RuntimeError( # pragma: no cover "DTLS socket must be bound before it can serve" ) from None self._ensure_receive_loop() diff --git a/trio/_tests/test_deprecate.py b/trio/_tests/test_deprecate.py index 91bcc65c4c..efacb27b3a 100644 --- a/trio/_tests/test_deprecate.py +++ b/trio/_tests/test_deprecate.py @@ -259,7 +259,7 @@ def test_module_with_deprecations(recwarn_always: pytest.WarningsRecorder) -> No assert "instead-string instead" in got.message.args[0] with pytest.raises(AttributeError): - module_with_deprecations.asdf # type: ignore[attr-defined] # noqa: B018 + module_with_deprecations.asdf # type: ignore[attr-defined] # noqa: B018 # "useless expression" def test_tests_is_deprecated1() -> None: diff --git a/trio/testing/_fake_net.py b/trio/testing/_fake_net.py index 9dc0f1ee9a..d51814f6cf 100644 --- a/trio/testing/_fake_net.py +++ b/trio/testing/_fake_net.py @@ -33,7 +33,7 @@ def _family_for(ip: IPAddress) -> int: return trio.socket.AF_INET elif isinstance(ip, ipaddress.IPv6Address): return trio.socket.AF_INET6 - raise AssertionError() # pragma: no cover + raise NotImplementedError() # pragma: no cover def _wildcard_ip_for(family: int) -> IPAddress: @@ -41,8 +41,8 @@ def _wildcard_ip_for(family: int) -> IPAddress: return ipaddress.ip_address("0.0.0.0") elif family == trio.socket.AF_INET6: return ipaddress.ip_address("::") - else: - raise AssertionError() + else: # pragma: no cover + raise NotImplementedError() def _localhost_ip_for(family: int) -> IPAddress: @@ -50,8 +50,8 @@ def _localhost_ip_for(family: int) -> IPAddress: return ipaddress.ip_address("127.0.0.1") elif family == trio.socket.AF_INET6: return ipaddress.ip_address("::1") - else: - raise AssertionError() + else: # pragma: no cover + raise NotImplementedError() def _fake_err(code): From e1fdebc838bbec1682583137ae6b8becc3e0fa9a Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 16 Oct 2023 17:10:53 -0500 Subject: [PATCH 10/12] Add reasons to `NotImplementedError`s --- trio/testing/_fake_net.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/trio/testing/_fake_net.py b/trio/testing/_fake_net.py index d51814f6cf..74bda92e34 100644 --- a/trio/testing/_fake_net.py +++ b/trio/testing/_fake_net.py @@ -33,7 +33,7 @@ def _family_for(ip: IPAddress) -> int: return trio.socket.AF_INET elif isinstance(ip, ipaddress.IPv6Address): return trio.socket.AF_INET6 - raise NotImplementedError() # pragma: no cover + raise NotImplementedError("Unhandled IPAddress instance type") # pragma: no cover def _wildcard_ip_for(family: int) -> IPAddress: @@ -41,8 +41,7 @@ def _wildcard_ip_for(family: int) -> IPAddress: return ipaddress.ip_address("0.0.0.0") elif family == trio.socket.AF_INET6: return ipaddress.ip_address("::") - else: # pragma: no cover - raise NotImplementedError() + raise NotImplementedError("Unhandled ip address family") # pragma: no cover def _localhost_ip_for(family: int) -> IPAddress: @@ -50,8 +49,7 @@ def _localhost_ip_for(family: int) -> IPAddress: return ipaddress.ip_address("127.0.0.1") elif family == trio.socket.AF_INET6: return ipaddress.ip_address("::1") - else: # pragma: no cover - raise NotImplementedError() + raise NotImplementedError("Unhandled ip address family") # pragma: no cover def _fake_err(code): From f80b22a5f6f30a51d1593ebda4416d7679a756c4 Mon Sep 17 00:00:00 2001 From: CoolCat467 <52022020+CoolCat467@users.noreply.github.com> Date: Mon, 16 Oct 2023 17:17:46 -0500 Subject: [PATCH 11/12] Added note in newsfragments about exception change --- newsfragments/2807.misc.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/2807.misc.rst diff --git a/newsfragments/2807.misc.rst b/newsfragments/2807.misc.rst new file mode 100644 index 0000000000..3d7857d79e --- /dev/null +++ b/newsfragments/2807.misc.rst @@ -0,0 +1 @@ +On windows, if SIO_BASE_HANDLE failed and SIO_BSP_HANDLE_POLL didn't return a different socket, runtime error will now raise from the OSError that indicated the issue so that in the event it does happen it might help with debugging. From 66ad218085a48531a0107f68a135caa20c059270 Mon Sep 17 00:00:00 2001 From: John Litborn <11260241+jakkdl@users.noreply.github.com> Date: Tue, 17 Oct 2023 11:54:12 +0200 Subject: [PATCH 12/12] Update _dtls.py fix weird sentence in comment --- trio/_dtls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trio/_dtls.py b/trio/_dtls.py index cc7756cee3..866687dc63 100644 --- a/trio/_dtls.py +++ b/trio/_dtls.py @@ -1305,7 +1305,7 @@ async def handler(dtls_channel): try: self.socket.getsockname() except OSError: - # TODO: Write test that makes triggers this + # TODO: Write test that triggers this raise RuntimeError( # pragma: no cover "DTLS socket must be bound before it can serve" ) from None