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 01/30] 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 adf2ccbe9b..0d84442d1b 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 2ddaf2e8e6..ed785cb640 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 332441a3a0..0691de3517 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 b5957a134e..0b68b80fdf 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 905e81c37a..ea807fe4d6 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 80b62d4777..7effe76b02 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 a8431f89db..46729685f1 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 cba7a8dec0..4cdcfbf77e 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 5beee4b22e..d80479618c 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 d87bd21022..a9c0e16062 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 c612222697..4a4271b0ea 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 27518406cb..29146b6b46 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 11ad2fc5fe..c8614a8e88 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 76c17086dd..50478af62b 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 1e7f4332d3..d4ec98355f 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 0a85c8ecb0..9b17f8d538 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 2c9dfff292..4e52fec245 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 b137a4e028..d40309cd38 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 df1cbc37bc..46ab0776e5 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 7e575aa92e..1b02c9ee73 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 30596aa4fb..734427a537 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 0032a551dc..98adf7efea 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 ca23c333c7..340264a2ce 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 68040cebf8..bdd5936fad 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 9926abff0f..f96a4feca3 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 4a870ed7a5..8c8d0faba2 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 17eb6afcc7..d0e89c22db 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 df9d2e74a3..641454d2ee 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 41ce5f27cb..68f9026e22 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 4cd460078a..2741f1a6f7 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 5acb9b993c..bdce508ff0 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 e7c15b5da0..9b49e3bfa0 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 749bedf8d0..e5a4b41bb3 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 add7798d05..8a06946cb1 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 314eaf4b94..ccacf90a72 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 02/30] 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 ea807fe4d6..bbb2ba2cc8 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 4cdcfbf77e..51d8c98992 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 d80479618c..2284ec01c5 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 4a4271b0ea..9dffe898e6 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 bdd5936fad..df7f5b33b6 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 bdce508ff0..5acb9b993c 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 03/30] 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 8a06946cb1..1c30d89826 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 ccacf90a72..0762a82f31 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 04/30] 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 ed785cb640..1334741c05 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 8dbfd9e95d..4063368b0c 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 05/30] 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 1334741c05..fbd3186ebc 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 672501f754..79d784537f 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 4063368b0c..9739ba04cb 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 2284ec01c5..2a2bee5ca8 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 d403cfa7a1..c25a54f194 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 d9afee83d4..809fb2824a 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 85691402b2..999f0755e6 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 9dffe898e6..189d5a5836 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 29146b6b46..33ee03ea29 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 50478af62b..677c1b0362 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 4e52fec245..2e42328f6d 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 46ab0776e5..48eac8c279 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 734427a537..6af3721852 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 0ce82e7846..013d130780 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 340264a2ce..4dc904910c 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 8c8d0faba2..e2c6febd11 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 06/30] 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 48eac8c279..0a0419fbcb 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 07/30] 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 2a2bee5ca8..2dc33e0f53 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 08/30] 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 2dc33e0f53..678874fec7 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 09/30] 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 d824814022..de2449755f 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 10/30] 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 33ee03ea29..85135c31c5 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 11/30] 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 10965e132b..f44581d1e5 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 12/30] 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 f44581d1e5..1e10155c92 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 13/30] 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 1e10155c92..86f742db3b 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 14/30] 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 86f742db3b..10965e132b 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 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 15/30] 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 7effe76b02..960f245825 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 9739ba04cb..308333a49e 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 999f0755e6..aafcf92082 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 85135c31c5..bef77b7688 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 d40309cd38..0929874e93 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 16/30] 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 0000000000..731232877b --- /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 fbd3186ebc..82e5251372 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 17/30] 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 960f245825..39df2849ba 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 18/30] 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 39df2849ba..6053ff5a9a 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 19/30] 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 6053ff5a9a..36dd571a69 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 20/30] 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 36dd571a69..bd84a483cb 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 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 21/30] 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 bd84a483cb..c4325a2860 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 79d784537f..46a7fdf700 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 308333a49e..892eb9df60 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 c25a54f194..823c7aab09 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 aafcf92082..7b39588048 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 0929874e93..5835a4d759 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 22/30] 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 df7f5b33b6..50fecae1fb 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 23/30] 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 9b49e3bfa0..b354fbf5d0 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 24/30] 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 2e42328f6d..a58136b75b 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 e2c6febd11..e58a40f515 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 2741f1a6f7..458d427298 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 25/30] 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 458d427298..7afd7b612a 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 26/30] 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 4dc904910c..e32e1957bb 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 50fecae1fb..7e83e3d484 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 d0e89c22db..6673ed00dc 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 27/30] 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 7e83e3d484..1c12ab9772 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 6673ed00dc..7b2fe44173 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 28/30] 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 1c12ab9772..628a70c1f4 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 29/30] 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 628a70c1f4..fda7eb54d8 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 30/30] 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 fda7eb54d8..e09fbc36d7 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()