diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d1b23f66d5..fba114f1f6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,22 +20,25 @@ repos: - id: sort-simple-yaml files: .pre-commit-config.yaml - repo: https://github.com/psf/black-pre-commit-mirror - rev: 24.10.0 + rev: 25.1.0 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.3 + rev: v0.9.6 hooks: - id: ruff types: [file] types_or: [python, pyi, toml] args: ["--show-fixes"] - repo: https://github.com/codespell-project/codespell - rev: v2.4.0 + rev: v2.4.1 hooks: - id: codespell + additional_dependencies: + # tomli needed on 3.10. tomllib is available in stdlib on 3.11+ + - tomli - repo: https://github.com/crate-ci/typos - rev: dictgen-v0.3.1 + rev: typos-dict-v0.12.4 hooks: - id: typos - repo: https://github.com/sphinx-contrib/sphinx-lint @@ -43,7 +46,7 @@ repos: hooks: - id: sphinx-lint - repo: https://github.com/woodruffw/zizmor-pre-commit - rev: v1.2.2 + rev: v1.3.1 hooks: - id: zizmor - repo: local @@ -56,7 +59,7 @@ repos: additional_dependencies: ["astor", "attrs", "black", "ruff"] files: ^src\/trio\/_core\/(_run|(_i(o_(common|epoll|kqueue|windows)|nstrumentation)))\.py$ - repo: https://github.com/astral-sh/uv-pre-commit - rev: 0.5.24 + rev: 0.5.30 hooks: # Compile requirements - id: pip-compile diff --git a/docs-requirements.in b/docs-requirements.in index 1a571d9832..7094b9e471 100644 --- a/docs-requirements.in +++ b/docs-requirements.in @@ -23,4 +23,5 @@ exceptiongroup >= 1.0.0rc9 immutables >= 0.6 # types used in annotations -pyOpenSSL +# TODO: fix support for importing typing-extensions +pyOpenSSL < 25.0.0 diff --git a/docs-requirements.txt b/docs-requirements.txt index 5827378796..7b5d481c8a 100644 --- a/docs-requirements.txt +++ b/docs-requirements.txt @@ -2,15 +2,15 @@ # uv pip compile --universal --python-version=3.11 docs-requirements.in -o docs-requirements.txt alabaster==1.0.0 # via sphinx -attrs==24.3.0 +attrs==25.1.0 # via # -r docs-requirements.in # outcome -babel==2.16.0 +babel==2.17.0 # via sphinx beautifulsoup4==4.12.3 # via sphinx-codeautolink -certifi==2024.12.14 +certifi==2025.1.31 # via requests cffi==1.17.1 ; os_name == 'nt' or platform_python_implementation != 'PyPy' # via @@ -24,7 +24,7 @@ colorama==0.4.6 ; sys_platform == 'win32' # via # click # sphinx -cryptography==44.0.0 +cryptography==44.0.1 # via pyopenssl docutils==0.21.2 # via @@ -53,7 +53,7 @@ packaging==24.2 # via sphinx pycparser==2.22 ; os_name == 'nt' or platform_python_implementation != 'PyPy' # via cffi -pygments==2.18.0 +pygments==2.19.1 # via sphinx pyopenssl==24.3.0 # via -r docs-requirements.in @@ -75,7 +75,7 @@ sphinx==8.1.3 # sphinx-rtd-theme # sphinxcontrib-jquery # sphinxcontrib-trio -sphinx-codeautolink==0.15.2 +sphinx-codeautolink==0.16.2 # via -r docs-requirements.in sphinx-hoverxref==1.4.2 # via -r docs-requirements.in diff --git a/docs/source/history.rst b/docs/source/history.rst index d3b25d08c4..6564164da3 100644 --- a/docs/source/history.rst +++ b/docs/source/history.rst @@ -5,6 +5,39 @@ Release history .. towncrier release notes start +Trio 0.29.0 (2025-02-14) +------------------------ + +Features +~~~~~~~~ + +- Add :func:`trio.lowlevel.in_trio_run` and :func:`trio.lowlevel.in_trio_task` and document the semantics (and differences) thereof. See :ref:`the documentation `. (`#2757 `__) +- If `trio.testing.RaisesGroup` does not get the expected exceptions it now raises an `AssertionError` with a helpful message, instead of letting the raised exception/group fall through. The raised exception is available in the ``__context__`` of the `AssertionError` and can be seen in the traceback. (`#3145 `__) + + +Bugfixes +~~~~~~~~ + +- Clear Trio's cache of worker threads upon `os.fork`. (`#2764 `__) + + +Miscellaneous internal changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- Stop using ctypes to mutate tracebacks for ``strict_exception_groups=False``'s exception collapsing. (`#405 `__) +- Fixed spelling error in Windows error code enum for ``ERROR_INVALID_PARAMETER``. (`#3166 `__) +- Publicly re-export ``__version__`` for type checking purposes. (`#3186 `__) +- The typing of :func:`trio.abc.HostnameResolver.getaddrinfo` has been corrected to + match that of the stdlib `socket.getaddrinfo`, which was updated in mypy 1.15 (via + a typeshed update) to include the possibility of ``tuple[int, bytes]`` for the + ``sockaddr`` field of the result. This happens in situations where Python was compiled + with ``--disable-ipv6``. + + Additionally, the static typing of :func:`trio.to_thread.run_sync`, + :func:`trio.from_thread.run` and :func:`trio.from_thread.run_sync` has been + improved and should reflect the underlying function being run. (`#3201 `__) + + Trio 0.28.0 (2024-12-25) ------------------------ diff --git a/newsfragments/2757.feature.rst b/newsfragments/2757.feature.rst deleted file mode 100644 index 317299561a..0000000000 --- a/newsfragments/2757.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Add :func:`trio.lowlevel.in_trio_run` and :func:`trio.lowlevel.in_trio_task` and document the semantics (and differences) thereof. See :ref:`the documentation `. diff --git a/newsfragments/3145.feature.rst b/newsfragments/3145.feature.rst deleted file mode 100644 index e049591912..0000000000 --- a/newsfragments/3145.feature.rst +++ /dev/null @@ -1 +0,0 @@ -If `trio.testing.RaisesGroup` does not get the expected exceptions it now raises an `AssertionError` with a helpful message, instead of letting the raised exception/group fall through. The raised exception is available in the ``__context__`` of the `AssertionError` and can be seen in the traceback. diff --git a/newsfragments/3166.breaking.rst b/newsfragments/3166.breaking.rst deleted file mode 100644 index ea2890bc23..0000000000 --- a/newsfragments/3166.breaking.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed spelling error in Windows CFFI ErrorCodes Enum ``ERROR_INVALID_PARAMETER`` diff --git a/newsfragments/3186.misc.rst b/newsfragments/3186.misc.rst deleted file mode 100644 index de85be80cb..0000000000 --- a/newsfragments/3186.misc.rst +++ /dev/null @@ -1 +0,0 @@ -Publicly re-export ``__version__`` for type checking purposes. diff --git a/pyproject.toml b/pyproject.toml index 25cac4ae08..ffc93e170f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -186,7 +186,7 @@ combine-as-imports = true fixture-parentheses = false [tool.mypy] -python_version = "3.9" +python_version = "3.10" files = ["src/trio/", "docs/source/*.py"] # Be flexible about dependencies that don't have stubs yet (like pytest) diff --git a/src/trio/__init__.py b/src/trio/__init__.py index 0b675ce473..f383c7b07e 100644 --- a/src/trio/__init__.py +++ b/src/trio/__init__.py @@ -1,5 +1,4 @@ -"""Trio - A friendly Python library for async concurrency and I/O -""" +"""Trio - A friendly Python library for async concurrency and I/O""" from __future__ import annotations diff --git a/src/trio/_abc.py b/src/trio/_abc.py index d981b8c9e7..abb6824381 100644 --- a/src/trio/_abc.py +++ b/src/trio/_abc.py @@ -178,7 +178,7 @@ async def getaddrinfo( socket.SocketKind, int, str, - tuple[str, int] | tuple[str, int, int, int], + tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], ] ]: """A custom implementation of :func:`~trio.socket.getaddrinfo`. diff --git a/src/trio/_core/_concat_tb.py b/src/trio/_core/_concat_tb.py index 18bd11bd19..9d0291ccf8 100644 --- a/src/trio/_core/_concat_tb.py +++ b/src/trio/_core/_concat_tb.py @@ -1,121 +1,10 @@ from __future__ import annotations -from typing import TYPE_CHECKING, ClassVar, cast - -if TYPE_CHECKING: - from types import TracebackType - -################################################################ -# concat_tb -################################################################ - -# We need to compute a new traceback that is the concatenation of two existing -# tracebacks. This requires copying the entries in 'head' and then pointing -# the final tb_next to 'tail'. -# -# NB: 'tail' might be None, which requires some special handling in the ctypes -# version. -# -# The complication here is that Python doesn't actually support copying or -# modifying traceback objects, so we have to get creative... -# -# On CPython, we use ctypes. On PyPy, we use "transparent proxies". -# -# Jinja2 is a useful source of inspiration: -# https://github.com/pallets/jinja/blob/main/src/jinja2/debug.py - -try: - import tputil -except ImportError: - # ctypes it is - # How to handle refcounting? I don't want to use ctypes.py_object because - # I don't understand or trust it, and I don't want to use - # ctypes.pythonapi.Py_{Inc,Dec}Ref because we might clash with user code - # that also tries to use them but with different types. So private _ctypes - # APIs it is! - import _ctypes - import ctypes - - class CTraceback(ctypes.Structure): - _fields_: ClassVar = [ - ("PyObject_HEAD", ctypes.c_byte * object().__sizeof__()), - ("tb_next", ctypes.c_void_p), - ("tb_frame", ctypes.c_void_p), - ("tb_lasti", ctypes.c_int), - ("tb_lineno", ctypes.c_int), - ] - - def copy_tb(base_tb: TracebackType, tb_next: TracebackType | None) -> TracebackType: - # TracebackType has no public constructor, so allocate one the hard way - try: - raise ValueError - except ValueError as exc: - new_tb = exc.__traceback__ - assert new_tb is not None - c_new_tb = CTraceback.from_address(id(new_tb)) - - # At the C level, tb_next either points to the next traceback or is - # NULL. c_void_p and the .tb_next accessor both convert NULL to None, - # but we shouldn't DECREF None just because we assigned to a NULL - # pointer! Here we know that our new traceback has only 1 frame in it, - # so we can assume the tb_next field is NULL. - assert c_new_tb.tb_next is None - # If tb_next is None, then we want to set c_new_tb.tb_next to NULL, - # which it already is, so we're done. Otherwise, we have to actually - # do some work: - if tb_next is not None: - _ctypes.Py_INCREF(tb_next) - c_new_tb.tb_next = id(tb_next) - - assert c_new_tb.tb_frame is not None - _ctypes.Py_INCREF(base_tb.tb_frame) - old_tb_frame = new_tb.tb_frame - c_new_tb.tb_frame = id(base_tb.tb_frame) - _ctypes.Py_DECREF(old_tb_frame) - - c_new_tb.tb_lasti = base_tb.tb_lasti - c_new_tb.tb_lineno = base_tb.tb_lineno - - try: - return new_tb - finally: - # delete references from locals to avoid creating cycles - # see test_cancel_scope_exit_doesnt_create_cyclic_garbage - del new_tb, old_tb_frame - -else: - # http://doc.pypy.org/en/latest/objspace-proxies.html - 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( # type: ignore[no-any-unimported] - operation: tputil.ProxyOperation, - ) -> 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 - # no missing test we could add, and no value in coverage nagging - # us about adding one. - if ( - operation.opname - in { - "__getattribute__", - "__getattr__", - } - and operation.args[0] == "tb_next" - ) or TYPE_CHECKING: # pragma: no cover - return tb_next - # Delegate is reverting to original behaviour - return operation.delegate() # type: ignore[no-any-return] - - return cast( - "TracebackType", - tputil.make_proxy(controller, type(base_tb), base_tb), - ) # Returns proxy to traceback +from types import TracebackType # this is used for collapsing single-exception ExceptionGroups when using -# `strict_exception_groups=False`. Once that is retired this function and its helper can +# `strict_exception_groups=False`. Once that is retired this function can # be removed as well. def concat_tb( head: TracebackType | None, @@ -131,5 +20,7 @@ def concat_tb( pointer = pointer.tb_next current_head = tail for head_tb in reversed(head_tbs): - current_head = copy_tb(head_tb, tb_next=current_head) + current_head = TracebackType( + current_head, head_tb.tb_frame, head_tb.tb_lasti, head_tb.tb_lineno + ) return current_head diff --git a/src/trio/_core/_entry_queue.py b/src/trio/_core/_entry_queue.py index 0691de3517..988b45ca00 100644 --- a/src/trio/_core/_entry_queue.py +++ b/src/trio/_core/_entry_queue.py @@ -16,8 +16,7 @@ PosArgsT = TypeVarTuple("PosArgsT") -# Explicit "Any" is not allowed -Function = Callable[..., object] # type: ignore[misc] +Function = Callable[..., object] # type: ignore[explicit-any] Job = tuple[Function, tuple[object, ...]] diff --git a/src/trio/_core/_instrumentation.py b/src/trio/_core/_instrumentation.py index 40bddd1a23..57f351d18c 100644 --- a/src/trio/_core/_instrumentation.py +++ b/src/trio/_core/_instrumentation.py @@ -2,23 +2,22 @@ import logging import types -from collections.abc import Callable, Sequence -from typing import TypeVar +from typing import TYPE_CHECKING, TypeVar from .._abc import Instrument # Used to log exceptions in instruments INSTRUMENT_LOGGER = logging.getLogger("trio.abc.Instrument") +if TYPE_CHECKING: + from collections.abc import Sequence -# Explicit "Any" is not allowed -F = TypeVar("F", bound=Callable[..., object]) # type: ignore[misc] + T = TypeVar("T") # 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: F) -> F: # type: ignore[misc] +def _public(fn: T) -> T: return fn diff --git a/src/trio/_core/_run.py b/src/trio/_core/_run.py index eedb996441..8649c0f704 100644 --- a/src/trio/_core/_run.py +++ b/src/trio/_core/_run.py @@ -61,7 +61,6 @@ from collections.abc import ( Awaitable, Callable, - Coroutine, Generator, Iterator, Sequence, @@ -1303,8 +1302,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] + async def start( # type: ignore[explicit-any] self, async_fn: Callable[..., Awaitable[object]], *args: object, @@ -1404,10 +1402,9 @@ def __del__(self) -> None: @final @attrs.define(eq=False, repr=False) -class Task(metaclass=NoPublicConstructor): # type: ignore[misc] +class Task(metaclass=NoPublicConstructor): # type: ignore[explicit-any] _parent_nursery: Nursery | None - # Explicit "Any" is not allowed - coro: Coroutine[Any, Outcome[object], Any] # type: ignore[misc] + coro: types.CoroutineType[Any, Outcome[object], Any] # type: ignore[explicit-any] _runner: Runner name: str context: contextvars.Context @@ -1425,11 +1422,10 @@ class Task(metaclass=NoPublicConstructor): # type: ignore[misc] # tracebacks with extraneous frames. # - for scheduled tasks, custom_sleep_data is None # Tasks start out unscheduled. - # Explicit "Any" is not allowed - _next_send_fn: Callable[[Any], object] | None = None # type: ignore[misc] - _next_send: Outcome[Any] | BaseException | None = None # type: ignore[misc] + _next_send_fn: Callable[[Any], object] | None = None # type: ignore[explicit-any] + _next_send: Outcome[Any] | BaseException | None = None # type: ignore[explicit-any] _abort_func: Callable[[_core.RaiseCancelT], Abort] | None = None - custom_sleep_data: Any = None # type: ignore[misc] + custom_sleep_data: Any = None # type: ignore[explicit-any] # For introspection and nursery.start() _child_nurseries: list[Nursery] = attrs.Factory(list) @@ -1497,7 +1493,7 @@ def print_stack_for_task(task): """ # Ignore static typing as we're doing lots of dynamic introspection - coro: Any = self.coro # type: ignore[misc] + coro: Any = self.coro # type: ignore[explicit-any] while coro is not None: if hasattr(coro, "cr_frame"): # A real coroutine @@ -1642,16 +1638,13 @@ class RunStatistics: @attrs.define(eq=False) -# Explicit "Any" is not allowed -class GuestState: # type: ignore[misc] +class GuestState: # type: ignore[explicit-any] runner: Runner run_sync_soon_threadsafe: Callable[[Callable[[], object]], object] run_sync_soon_not_threadsafe: Callable[[Callable[[], object]], object] - # Explicit "Any" is not allowed - done_callback: Callable[[Outcome[Any]], object] # type: ignore[misc] + done_callback: Callable[[Outcome[Any]], object] # type: ignore[explicit-any] unrolled_run_gen: Generator[float, EventResult, None] - # Explicit "Any" is not allowed - unrolled_run_next_send: Outcome[Any] = attrs.Factory(lambda: Value(None)) # type: ignore[misc] + unrolled_run_next_send: Outcome[Any] = attrs.Factory(lambda: Value(None)) # type: ignore[explicit-any] def guest_tick(self) -> None: prev_library, sniffio_library.name = sniffio_library.name, "trio" @@ -1696,8 +1689,7 @@ def in_main_thread() -> None: @attrs.define(eq=False) -# Explicit "Any" is not allowed -class Runner: # type: ignore[misc] +class Runner: # type: ignore[explicit-any] clock: Clock instruments: Instruments io_manager: TheIOManager @@ -1705,8 +1697,7 @@ class Runner: # type: ignore[misc] strict_exception_groups: bool # Run-local values, see _local.py - # Explicit "Any" is not allowed - _locals: dict[_core.RunVar[Any], object] = attrs.Factory(dict) # type: ignore[misc] + _locals: dict[_core.RunVar[Any], object] = attrs.Factory(dict) # type: ignore[explicit-any] runq: deque[Task] = attrs.Factory(deque) tasks: set[Task] = attrs.Factory(set) @@ -1895,7 +1886,7 @@ async def python_wrapper(orig_coro: Awaitable[RetT]) -> RetT: return await orig_coro coro = python_wrapper(coro) - assert coro.cr_frame is not None, "Coroutine frame should exist" + assert coro.cr_frame is not None, "Coroutine frame should exist" # type: ignore[attr-defined] ###### # Set up the Task object @@ -2133,8 +2124,7 @@ 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 - # Explicit "Any" is not allowed - waiting_for_idle: Any = attrs.Factory(SortedDict) # type: ignore[misc] + waiting_for_idle: Any = attrs.Factory(SortedDict) # type: ignore[explicit-any] @_public async def wait_all_tasks_blocked(self, cushion: float = 0.0) -> None: @@ -2435,8 +2425,7 @@ def run( raise AssertionError(runner.main_task_outcome) -# Explicit .../"Any" not allowed -def start_guest_run( # type: ignore[misc] +def start_guest_run( # type: ignore[explicit-any] async_fn: Callable[..., Awaitable[RetT]], *args: object, run_sync_soon_threadsafe: Callable[[Callable[[], object]], object], diff --git a/src/trio/_core/_tests/test_asyncgen.py b/src/trio/_core/_tests/test_asyncgen.py index 588c54dae8..8147a0e57b 100644 --- a/src/trio/_core/_tests/test_asyncgen.py +++ b/src/trio/_core/_tests/test_asyncgen.py @@ -4,6 +4,7 @@ import sys import weakref from math import inf +from types import AsyncGeneratorType from typing import TYPE_CHECKING, NoReturn import pytest @@ -88,6 +89,7 @@ async def async_main() -> None: _core.run(async_main) assert collected.pop() == "outlived run" for agen in saved: + assert isinstance(agen, AsyncGeneratorType) assert agen.ag_frame is None # all should now be exhausted @@ -301,9 +303,11 @@ def test_delegation_to_existing_hooks() -> None: record = [] def my_firstiter(agen: AsyncGenerator[object, NoReturn]) -> None: + assert isinstance(agen, AsyncGeneratorType) record.append("firstiter " + agen.ag_frame.f_locals["arg"]) def my_finalizer(agen: AsyncGenerator[object, NoReturn]) -> None: + assert isinstance(agen, AsyncGeneratorType) record.append("finalizer " + agen.ag_frame.f_locals["arg"]) async def example(arg: str) -> AsyncGenerator[int, None]: diff --git a/src/trio/_core/_tests/test_ki.py b/src/trio/_core/_tests/test_ki.py index 67c83e8358..07a7558720 100644 --- a/src/trio/_core/_tests/test_ki.py +++ b/src/trio/_core/_tests/test_ki.py @@ -165,7 +165,7 @@ def protected_manager() -> Iterator[None]: async def test_async_generator_agen_protection() -> None: @_core.enable_ki_protection @async_generator # type: ignore[misc] # untyped generator - async def agen_protected1() -> None: + async def agen_protected1() -> None: # type: ignore[misc] # untyped generator assert _core.currently_ki_protected() try: await yield_() @@ -174,7 +174,7 @@ async def agen_protected1() -> None: @_core.disable_ki_protection @async_generator # type: ignore[misc] # untyped generator - async def agen_unprotected1() -> None: + async def agen_unprotected1() -> None: # type: ignore[misc] # untyped generator assert not _core.currently_ki_protected() try: await yield_() @@ -184,7 +184,7 @@ async def agen_unprotected1() -> None: # Swap the order of the decorators: @async_generator # type: ignore[misc] # untyped generator @_core.enable_ki_protection - async def agen_protected2() -> None: + async def agen_protected2() -> None: # type: ignore[misc] # untyped generator assert _core.currently_ki_protected() try: await yield_() @@ -193,7 +193,7 @@ async def agen_protected2() -> None: @async_generator # type: ignore[misc] # untyped generator @_core.disable_ki_protection - async def agen_unprotected2() -> None: + async def agen_unprotected2() -> None: # type: ignore[misc] # untyped generator assert not _core.currently_ki_protected() try: await yield_() @@ -677,9 +677,8 @@ async def _consume_async_generator(agen: AsyncGenerator[None, None]) -> None: await agen.aclose() -# Explicit .../"Any" is not allowed -def _consume_function_for_coverage( # type: ignore[misc] - fn: Callable[..., object], +def _consume_function_for_coverage( + fn: Callable[[], object], ) -> None: result = fn() if inspect.isasyncgen(result): diff --git a/src/trio/_core/_tests/test_run.py b/src/trio/_core/_tests/test_run.py index 576b807f9d..289a356672 100644 --- a/src/trio/_core/_tests/test_run.py +++ b/src/trio/_core/_tests/test_run.py @@ -1658,8 +1658,7 @@ async def func1(expected: str) -> None: async def func2() -> None: # pragma: no cover pass - # Explicit .../"Any" is not allowed - async def check( # type: ignore[misc] + async def check( # type: ignore[explicit-any] spawn_fn: Callable[..., object], ) -> None: spawn_fn(func1, "func1") @@ -1696,14 +1695,13 @@ 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 - def bad_call_run( # type: ignore[misc] + def bad_call_run( # type: ignore[explicit-any] func: Callable[..., Awaitable[object]], *args: tuple[object, ...], ) -> None: _core.run(func, *args) - def bad_call_spawn( # type: ignore[misc] + def bad_call_spawn( # type: ignore[explicit-any] func: Callable[..., Awaitable[object]], *args: tuple[object, ...], ) -> None: diff --git a/src/trio/_core/_tests/test_thread_cache.py b/src/trio/_core/_tests/test_thread_cache.py index 1e3841ee0d..a308befb67 100644 --- a/src/trio/_core/_tests/test_thread_cache.py +++ b/src/trio/_core/_tests/test_thread_cache.py @@ -1,5 +1,6 @@ from __future__ import annotations +import os import threading import time from contextlib import contextmanager @@ -195,3 +196,47 @@ def deliver(_: object) -> NoReturn: err = capfd.readouterr().err assert "don't do this" in err assert "delivering result" in err + + +@pytest.mark.skipif(not hasattr(os, "fork"), reason="os.fork isn't supported") +def test_clear_thread_cache_after_fork() -> None: + assert hasattr(os, "fork") + + def foo() -> None: + pass + + # ensure the thread cache exists + done = threading.Event() + start_thread_soon(foo, lambda _: done.set()) + done.wait() + + child_pid = os.fork() + + # try using it + done = threading.Event() + start_thread_soon(foo, lambda _: done.set()) + done.wait() + + if child_pid != 0: + # if this test fails, this will hang, triggering a timeout. + os.waitpid(child_pid, 0) + else: + # this is necessary because os._exit doesn't unwind the stack, + # so coverage doesn't get to automatically stop and save + # coverage information. + try: + import coverage + + cov = coverage.Coverage.current() + # the following pragmas are necessary because if coverage: + # - isn't running, then it can't record the branch not + # taken + # - isn't installed, then it can't record the ImportError + + if cov: # pragma: no branch + cov.stop() + cov.save() + except ImportError: # pragma: no cover + pass + + os._exit(0) # pragma: no cover # coverage was stopped above. diff --git a/src/trio/_core/_thread_cache.py b/src/trio/_core/_thread_cache.py index 189d5a5836..44820e7711 100644 --- a/src/trio/_core/_thread_cache.py +++ b/src/trio/_core/_thread_cache.py @@ -2,6 +2,7 @@ import ctypes import ctypes.util +import os import sys import traceback from functools import partial @@ -215,8 +216,7 @@ class ThreadCache: __slots__ = ("_idle_workers",) def __init__(self) -> None: - # Explicit "Any" not allowed - self._idle_workers: dict[WorkerThread[Any], None] = {} # type: ignore[misc] + self._idle_workers: dict[WorkerThread[Any], None] = {} # type: ignore[explicit-any] def start_thread_soon( self, @@ -301,3 +301,15 @@ def start_thread_soon( """ THREAD_CACHE.start_thread_soon(fn, deliver, name) + + +def clear_worker_threads() -> None: + # This is OK because the child process does not actually have any + # worker threads. Additionally, while WorkerThread keeps a strong + # reference and so would get affected, the only place those are + # stored is here. + THREAD_CACHE._idle_workers.clear() + + +if hasattr(os, "register_at_fork"): + os.register_at_fork(after_in_child=clear_worker_threads) diff --git a/src/trio/_core/_traps.py b/src/trio/_core/_traps.py index 1ddd5628ba..60f72d1295 100644 --- a/src/trio/_core/_traps.py +++ b/src/trio/_core/_traps.py @@ -104,8 +104,7 @@ class Abort(enum.Enum): # Should always return the type a Task "expects", unless you willfully reschedule it # with a bad value. -# Explicit "Any" is not allowed -async def wait_task_rescheduled( # type: ignore[misc] +async def wait_task_rescheduled( # type: ignore[explicit-any] abort_func: Callable[[RaiseCancelT], Abort], ) -> Any: """Put the current task to sleep, with cancellation support. diff --git a/src/trio/_file_io.py b/src/trio/_file_io.py index 5307fb9425..443dcdfb40 100644 --- a/src/trio/_file_io.py +++ b/src/trio/_file_io.py @@ -428,7 +428,7 @@ async def open_file( @overload -async def open_file( # type: ignore[misc] # Any usage matches builtins.open(). +async def open_file( # type: ignore[explicit-any, misc] # Any usage matches builtins.open(). file: _OpenFile, mode: str, buffering: int = -1, diff --git a/src/trio/_highlevel_open_tcp_stream.py b/src/trio/_highlevel_open_tcp_stream.py index d4ec98355f..5723180e46 100644 --- a/src/trio/_highlevel_open_tcp_stream.py +++ b/src/trio/_highlevel_open_tcp_stream.py @@ -8,7 +8,7 @@ from trio.socket import SOCK_STREAM, SocketType, getaddrinfo, socket if TYPE_CHECKING: - from collections.abc import Generator + from collections.abc import Generator, MutableSequence from socket import AddressFamily, SocketKind from trio._socket import AddressFormat @@ -134,9 +134,8 @@ def close_all() -> Generator[set[SocketType], None, None]: raise BaseExceptionGroup("", errs) -# Explicit "Any" is not allowed -def reorder_for_rfc_6555_section_5_4( # type: ignore[misc] - targets: list[tuple[AddressFamily, SocketKind, int, str, Any]], +def reorder_for_rfc_6555_section_5_4( # type: ignore[explicit-any] + targets: MutableSequence[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 diff --git a/src/trio/_highlevel_serve_listeners.py b/src/trio/_highlevel_serve_listeners.py index 9b17f8d538..008caaabea 100644 --- a/src/trio/_highlevel_serve_listeners.py +++ b/src/trio/_highlevel_serve_listeners.py @@ -25,8 +25,7 @@ StreamT = TypeVar("StreamT", bound=trio.abc.AsyncResource) -# Explicit "Any" is not allowed -ListenerT = TypeVar("ListenerT", bound=trio.abc.Listener[Any]) # type: ignore[misc] +ListenerT = TypeVar("ListenerT", bound=trio.abc.Listener[Any]) # type: ignore[explicit-any] Handler = Callable[[StreamT], Awaitable[object]] @@ -68,8 +67,7 @@ async def _serve_one_listener( # https://github.com/python/typing/issues/548 -# Explicit "Any" is not allowed -async def serve_listeners( # type: ignore[misc] +async def serve_listeners( # type: ignore[explicit-any] handler: Handler[StreamT], listeners: list[ListenerT], *, diff --git a/src/trio/_path.py b/src/trio/_path.py index a58136b75b..53bd0a700f 100644 --- a/src/trio/_path.py +++ b/src/trio/_path.py @@ -30,8 +30,7 @@ T = TypeVar("T") -# Explicit .../"Any" is not allowed -def _wraps_async( # type: ignore[misc] +def _wraps_async( # type: ignore[explicit-any] wrapped: Callable[..., object], ) -> Callable[[Callable[P, T]], Callable[P, Awaitable[T]]]: def decorator(fn: Callable[P, T]) -> Callable[P, Awaitable[T]]: @@ -184,7 +183,7 @@ async def open( ) -> AsyncIOWrapper[BinaryIO]: ... @overload - async def open( # type: ignore[misc] # Any usage matches builtins.open(). + async def open( # type: ignore[misc, explicit-any] # Any usage matches builtins.open(). self, mode: str, buffering: int = -1, @@ -193,8 +192,8 @@ async def open( # type: ignore[misc] # Any usage matches builtins.open(). newline: str | None = None, ) -> AsyncIOWrapper[IO[Any]]: ... - @_wraps_async(pathlib.Path.open) # type: ignore[misc] # Overload return mismatch. - def open(self, *args: Any, **kwargs: Any) -> AsyncIOWrapper[IO[Any]]: + @_wraps_async(pathlib.Path.open) + def open(self, *args: Any, **kwargs: Any) -> AsyncIOWrapper[IO[Any]]: # type: ignore[misc, explicit-any] # Overload return mismatch. return wrap_file(self._wrapped_cls(self).open(*args, **kwargs)) def __repr__(self) -> str: diff --git a/src/trio/_socket.py b/src/trio/_socket.py index 4dde512985..003f6c41df 100644 --- a/src/trio/_socket.py +++ b/src/trio/_socket.py @@ -46,8 +46,7 @@ # most users, so currently we just specify it as `Any`. Otherwise we would write: # `AddressFormat = TypeVar("AddressFormat")` # but instead we simply do: -# Explicit "Any" is not allowed -AddressFormat: TypeAlias = Any # type: ignore[misc] +AddressFormat: TypeAlias = Any # type: ignore[explicit-any] # Usage: @@ -182,7 +181,7 @@ async def getaddrinfo( SocketKind, int, str, - tuple[str, int] | tuple[str, int, int, int], + tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], ] ]: """Look up a numeric address given a name. diff --git a/src/trio/_ssl.py b/src/trio/_ssl.py index 0a0419fbcb..52c5137ea1 100644 --- a/src/trio/_ssl.py +++ b/src/trio/_ssl.py @@ -423,8 +423,7 @@ def __init__( "version", } - # Explicit "Any" is not allowed - def __getattr__( # type: ignore[misc] + def __getattr__( # type: ignore[explicit-any] self, name: str, ) -> Any: diff --git a/src/trio/_tests/test_highlevel_open_tcp_listeners.py b/src/trio/_tests/test_highlevel_open_tcp_listeners.py index 57a2e530d9..a770217096 100644 --- a/src/trio/_tests/test_highlevel_open_tcp_listeners.py +++ b/src/trio/_tests/test_highlevel_open_tcp_listeners.py @@ -255,7 +255,7 @@ async def getaddrinfo( SocketKind, int, str, - tuple[str, int] | tuple[str, int, int, int], + tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], ] ]: assert isinstance(port, int) diff --git a/src/trio/_tests/test_highlevel_open_tcp_stream.py b/src/trio/_tests/test_highlevel_open_tcp_stream.py index d03e472503..eaec52ad4e 100644 --- a/src/trio/_tests/test_highlevel_open_tcp_stream.py +++ b/src/trio/_tests/test_highlevel_open_tcp_stream.py @@ -287,9 +287,9 @@ def _ip_to_gai_entry(self, ip: str) -> tuple[ SocketKind, int, str, - tuple[str, int, int, int] | tuple[str, int], + tuple[str, int, int, int] | tuple[str, int] | tuple[int, bytes], ]: - sockaddr: tuple[str, int] | tuple[str, int, int, int] + sockaddr: tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes] if ":" in ip: family = trio.socket.AF_INET6 sockaddr = (ip, self.port, 0, 0) @@ -312,7 +312,7 @@ async def getaddrinfo( SocketKind, int, str, - tuple[str, int, int, int] | tuple[str, int], + tuple[str, int, int, int] | tuple[str, int] | tuple[int, bytes], ] ]: assert host == b"test.example.com" diff --git a/src/trio/_tests/test_highlevel_ssl_helpers.py b/src/trio/_tests/test_highlevel_ssl_helpers.py index e42f311981..8c60c25f2c 100644 --- a/src/trio/_tests/test_highlevel_ssl_helpers.py +++ b/src/trio/_tests/test_highlevel_ssl_helpers.py @@ -45,7 +45,7 @@ async def echo_handler(stream: Stream) -> None: # you ask for. @attrs.define(slots=False) class FakeHostnameResolver(trio.abc.HostnameResolver): - sockaddr: tuple[str, int] | tuple[str, int, int, int] + sockaddr: tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes] async def getaddrinfo( self, @@ -61,7 +61,7 @@ async def getaddrinfo( SocketKind, int, str, - tuple[str, int] | tuple[str, int, int, int], + tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], ] ]: return [(AF_INET, SOCK_STREAM, IPPROTO_TCP, "", self.sockaddr)] diff --git a/src/trio/_tests/test_socket.py b/src/trio/_tests/test_socket.py index f4c963f4a3..5cd48ad1b4 100644 --- a/src/trio/_tests/test_socket.py +++ b/src/trio/_tests/test_socket.py @@ -30,7 +30,7 @@ SocketKind, int, str, - Union[tuple[str, int], tuple[str, int, int, int]], + Union[tuple[str, int], tuple[str, int, int, int], tuple[int, bytes]], ] GetAddrInfoResponse: TypeAlias = list[GaiTuple] GetAddrInfoArgs: TypeAlias = tuple[ @@ -186,7 +186,7 @@ def interesting_fields( ) -> tuple[ AddressFamily, SocketKind, - tuple[str, int] | tuple[str, int, int] | tuple[str, int, int, int], + tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], ]: # (family, type, proto, canonname, sockaddr) family, type_, _proto, _canonname, sockaddr = gai_tup @@ -198,7 +198,7 @@ def filtered( tuple[ AddressFamily, SocketKind, - tuple[str, int] | tuple[str, int, int] | tuple[str, int, int, int], + tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], ] ]: return [interesting_fields(gai_tup) for gai_tup in gai_list] diff --git a/src/trio/_tests/test_ssl.py b/src/trio/_tests/test_ssl.py index d271743c7a..5427ee65ae 100644 --- a/src/trio/_tests/test_ssl.py +++ b/src/trio/_tests/test_ssl.py @@ -381,8 +381,7 @@ def virtual_ssl_echo_server( yield SSLStream(fakesock, client_ctx, server_hostname="trio-test-1.example.org") -# Explicit "Any" is not allowed -def ssl_wrap_pair( # type: ignore[misc] +def ssl_wrap_pair( # type: ignore[explicit-any] client_ctx: SSLContext, client_transport: T_Stream, server_transport: T_Stream, diff --git a/src/trio/_tests/test_subprocess.py b/src/trio/_tests/test_subprocess.py index 638ba4c14f..15c88be25e 100644 --- a/src/trio/_tests/test_subprocess.py +++ b/src/trio/_tests/test_subprocess.py @@ -82,8 +82,8 @@ def SLEEP(seconds: int) -> list[str]: return python(f"import time; time.sleep({seconds})") -@asynccontextmanager # type: ignore[misc] # Any in decorated -async def open_process_then_kill( +@asynccontextmanager +async def open_process_then_kill( # type: ignore[misc, explicit-any] *args: Any, **kwargs: Any, ) -> AsyncIterator[Process]: @@ -95,8 +95,8 @@ async def open_process_then_kill( await proc.wait() -@asynccontextmanager # type: ignore[misc] # Any in decorated -async def run_process_in_nursery( +@asynccontextmanager +async def run_process_in_nursery( # type: ignore[misc, explicit-any] *args: Any, **kwargs: Any, ) -> AsyncIterator[Process]: @@ -115,8 +115,7 @@ async def run_process_in_nursery( ids=["open_process", "run_process in nursery"], ) -# Explicit .../"Any" is not allowed -BackgroundProcessType: TypeAlias = Callable[ # type: ignore[misc] +BackgroundProcessType: TypeAlias = Callable[ # type: ignore[explicit-any] ..., AbstractAsyncContextManager[Process], ] diff --git a/src/trio/_tests/test_threads.py b/src/trio/_tests/test_threads.py index 822385a3a5..380da3833b 100644 --- a/src/trio/_tests/test_threads.py +++ b/src/trio/_tests/test_threads.py @@ -55,8 +55,7 @@ async def test_do_in_trio_thread() -> None: trio_thread = threading.current_thread() - # Explicit "Any" is not allowed - async def check_case( # type: ignore[misc] + async def check_case( # type: ignore[explicit-any] do_in_trio_thread: Callable[..., threading.Thread], fn: Callable[..., T | Awaitable[T]], expected: tuple[str, T], @@ -207,7 +206,7 @@ def inner(name: str = "inner" + ending) -> threading.Thread: assert threading.current_thread().name == name return threading.current_thread() - def f(name: str) -> Callable[[None], threading.Thread]: + def f(name: str) -> Callable[[], threading.Thread]: return partial(inner, name) # test defaults @@ -285,7 +284,7 @@ def inner(name: str) -> threading.Thread: return threading.current_thread() - def f(name: str) -> Callable[[None], threading.Thread]: + def f(name: str) -> Callable[[], threading.Thread]: return partial(inner, name) # test defaults @@ -344,7 +343,7 @@ def g() -> NoReturn: async def test_run_in_worker_thread_cancellation() -> None: register: list[str | None] = [None] - def f(q: stdlib_queue.Queue[str]) -> None: + def f(q: stdlib_queue.Queue[None]) -> None: # Make the thread block for a controlled amount of time register[0] = "blocking" q.get() @@ -731,7 +730,7 @@ def sync_fn() -> None: # pragma: no cover pass with pytest.raises(TypeError, match="appears to be synchronous"): - await to_thread_run_sync(from_thread_run, sync_fn) + await to_thread_run_sync(from_thread_run, sync_fn) # type: ignore[arg-type] async def test_trio_from_thread_token() -> None: @@ -930,8 +929,7 @@ async def test_recursive_to_thread() -> None: def get_tid_then_reenter() -> int: nonlocal tid tid = threading.get_ident() - # The nesting of wrapper functions loses the return value of threading.get_ident - return from_thread_run(to_thread_run_sync, threading.get_ident) # type: ignore[no-any-return] + return from_thread_run(to_thread_run_sync, threading.get_ident) assert tid != await to_thread_run_sync(get_tid_then_reenter) diff --git a/src/trio/_threads.py b/src/trio/_threads.py index 7afd7b612a..394e5b06ac 100644 --- a/src/trio/_threads.py +++ b/src/trio/_threads.py @@ -29,8 +29,12 @@ if TYPE_CHECKING: from collections.abc import Awaitable, Callable, Generator + from typing_extensions import TypeVarTuple, Unpack + from trio._core._traps import RaiseCancelT + Ts = TypeVarTuple("Ts") + RetT = TypeVar("RetT") @@ -146,9 +150,8 @@ class ThreadPlaceholder: # Types for the to_thread_run_sync message loop @attrs.frozen(eq=False, slots=False) -# Explicit .../"Any" is not allowed -class Run(Generic[RetT]): # type: ignore[misc] - afn: Callable[..., Awaitable[RetT]] # type: ignore[misc] +class Run(Generic[RetT]): # type: ignore[explicit-any] + afn: Callable[..., Awaitable[RetT]] # type: ignore[explicit-any] args: tuple[object, ...] context: contextvars.Context = attrs.field( init=False, @@ -206,9 +209,8 @@ def in_trio_thread() -> None: @attrs.frozen(eq=False, slots=False) -# Explicit .../"Any" is not allowed -class RunSync(Generic[RetT]): # type: ignore[misc] - fn: Callable[..., RetT] # type: ignore[misc] +class RunSync(Generic[RetT]): # type: ignore[explicit-any] + fn: Callable[..., RetT] # type: ignore[explicit-any] args: tuple[object, ...] context: contextvars.Context = attrs.field( init=False, @@ -251,10 +253,10 @@ def run_in_system_nursery(self, token: TrioToken) -> None: token.run_sync_soon(self.run_sync) -@enable_ki_protection # Decorator used on function with Coroutine[Any, Any, RetT] -async def to_thread_run_sync( # type: ignore[misc] - sync_fn: Callable[..., RetT], - *args: object, +@enable_ki_protection +async def to_thread_run_sync( + sync_fn: Callable[[Unpack[Ts]], RetT], + *args: Unpack[Ts], thread_name: str | None = None, abandon_on_cancel: bool = False, limiter: CapacityLimiter | None = None, @@ -524,10 +526,9 @@ def _send_message_to_trio( return message_to_trio.queue.get().unwrap() -# Explicit "Any" is not allowed -def from_thread_run( # type: ignore[misc] - afn: Callable[..., Awaitable[RetT]], - *args: object, +def from_thread_run( + afn: Callable[[Unpack[Ts]], Awaitable[RetT]], + *args: Unpack[Ts], trio_token: TrioToken | None = None, ) -> RetT: """Run the given async function in the parent Trio thread, blocking until it @@ -569,10 +570,9 @@ def from_thread_run( # type: ignore[misc] return _send_message_to_trio(trio_token, Run(afn, args)) -# Explicit "Any" is not allowed -def from_thread_run_sync( # type: ignore[misc] - fn: Callable[..., RetT], - *args: object, +def from_thread_run_sync( + fn: Callable[[Unpack[Ts]], RetT], + *args: Unpack[Ts], trio_token: TrioToken | None = None, ) -> RetT: """Run the given sync function in the parent Trio thread, blocking until it diff --git a/src/trio/_util.py b/src/trio/_util.py index 8da2ef4ada..9b8b1d7a46 100644 --- a/src/trio/_util.py +++ b/src/trio/_util.py @@ -21,7 +21,7 @@ import trio # Explicit "Any" is not allowed -CallT = TypeVar("CallT", bound=Callable[..., Any]) # type: ignore[misc] +CallT = TypeVar("CallT", bound=Callable[..., Any]) # type: ignore[explicit-any] T = TypeVar("T") RetT = TypeVar("RetT") @@ -177,16 +177,14 @@ def __exit__( self._held = False -# Explicit "Any" is not allowed -def async_wraps( # type: ignore[misc] +def async_wraps( # type: ignore[explicit-any] cls: type[object], wrapped_cls: type[object], attr_name: str, ) -> Callable[[CallT], CallT]: """Similar to wraps, but for async wrappers of non-async functions.""" - # Explicit "Any" is not allowed - def decorator(func: CallT) -> CallT: # type: ignore[misc] + def decorator(func: CallT) -> CallT: # type: ignore[explicit-any] func.__name__ = attr_name func.__qualname__ = f"{cls.__qualname__}.{attr_name}" @@ -249,8 +247,7 @@ def open_memory_channel(max_buffer_size: int) -> Tuple[ but at least it becomes possible to write those. """ - # Explicit .../"Any" is not allowed - def __init__( # type: ignore[misc] + def __init__( # type: ignore[explicit-any] self, fn: Callable[..., RetT], ) -> None: @@ -346,11 +343,9 @@ def name_asyncgen(agen: AsyncGeneratorType[object, NoReturn]) -> str: # work around a pyright error if TYPE_CHECKING: - # Explicit .../"Any" is not allowed - Fn = TypeVar("Fn", bound=Callable[..., object]) # type: ignore[misc] + Fn = TypeVar("Fn", bound=Callable[..., object]) # type: ignore[explicit-any] - # Explicit .../"Any" is not allowed - def wraps( # type: ignore[misc] + def wraps( # type: ignore[explicit-any] wrapped: Callable[..., object], assigned: Sequence[str] = ..., updated: Sequence[str] = ..., diff --git a/src/trio/_version.py b/src/trio/_version.py index 11271535cb..6b7cf42081 100644 --- a/src/trio/_version.py +++ b/src/trio/_version.py @@ -1,3 +1,3 @@ # This file is imported from __init__.py and parsed by setuptools -__version__ = "0.28.0+dev" +__version__ = "0.29.0+dev" diff --git a/src/trio/testing/_fake_net.py b/src/trio/testing/_fake_net.py index 2f5bd624ae..5d63112e17 100644 --- a/src/trio/testing/_fake_net.py +++ b/src/trio/testing/_fake_net.py @@ -18,7 +18,6 @@ TYPE_CHECKING, Any, NoReturn, - TypeVar, Union, overload, ) @@ -82,9 +81,6 @@ def _scatter(data: bytes, buffers: Iterable[Buffer]) -> int: return written -T_UDPEndpoint = TypeVar("T_UDPEndpoint", bound="UDPEndpoint") - - @attrs.frozen class UDPEndpoint: ip: IPAddress @@ -101,9 +97,9 @@ def as_python_sockaddr(self) -> tuple[str, int] | tuple[str, int, int, int]: @classmethod def from_python_sockaddr( - cls: type[T_UDPEndpoint], + cls, sockaddr: tuple[str, int] | tuple[str, int, int, int], - ) -> T_UDPEndpoint: + ) -> UDPEndpoint: ip, port = sockaddr[:2] return cls(ip=ipaddress.ip_address(ip), port=port) @@ -155,7 +151,7 @@ async def getaddrinfo( SocketKind, int, str, - tuple[str, int] | tuple[str, int, int, int], + tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], ] ]: raise NotImplementedError("FakeNet doesn't do fake DNS yet") @@ -507,8 +503,7 @@ async def sendto( __address: tuple[object, ...] | str | Buffer | None, ) -> int: ... - # Explicit "Any" is not allowed - async def sendto( # type: ignore[misc] + async def sendto( # type: ignore[explicit-any] self, *args: Any, ) -> int: diff --git a/test-requirements.txt b/test-requirements.txt index 621486bd0d..2865e4c4a4 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,6 +1,8 @@ # This file was autogenerated by uv via the following command: # uv pip compile --universal --python-version=3.9 test-requirements.in -o test-requirements.txt -alabaster==0.7.16 +alabaster==0.7.16 ; python_full_version < '3.10' + # via sphinx +alabaster==1.0.0 ; python_full_version >= '3.10' # via sphinx astor==0.8.1 # via -r test-requirements.in @@ -8,15 +10,15 @@ astroid==3.3.8 # via pylint async-generator==1.10 # via -r test-requirements.in -attrs==24.3.0 +attrs==25.1.0 # via # -r test-requirements.in # outcome -babel==2.16.0 +babel==2.17.0 # via sphinx -black==24.10.0 ; implementation_name == 'cpython' +black==25.1.0 ; implementation_name == 'cpython' # via -r test-requirements.in -certifi==2024.12.14 +certifi==2025.1.31 # via requests cffi==1.17.1 ; os_name == 'nt' or platform_python_implementation != 'PyPy' # via @@ -28,7 +30,7 @@ charset-normalizer==3.4.1 # via requests click==8.1.8 ; implementation_name == 'cpython' # via black -codespell==2.4.0 +codespell==2.4.1 # via -r test-requirements.in colorama==0.4.6 ; sys_platform == 'win32' # via @@ -36,9 +38,9 @@ colorama==0.4.6 ; sys_platform == 'win32' # pylint # pytest # sphinx -coverage==7.6.10 +coverage==7.6.12 # via -r test-requirements.in -cryptography==44.0.0 +cryptography==44.0.1 # via # -r test-requirements.in # pyopenssl @@ -54,9 +56,9 @@ exceptiongroup==1.2.2 ; python_full_version < '3.11' # via # -r test-requirements.in # pytest -filelock==3.16.1 +filelock==3.17.0 # via virtualenv -identify==2.6.4 +identify==2.6.7 # via pre-commit idna==3.10 # via @@ -65,11 +67,11 @@ idna==3.10 # trustme imagesize==1.4.1 # via sphinx -importlib-metadata==8.5.0 ; python_full_version < '3.10' +importlib-metadata==8.6.1 ; python_full_version < '3.10' # via sphinx iniconfig==2.0.0 # via pytest -isort==5.13.2 +isort==6.0.0 # via pylint jedi==0.19.2 ; implementation_name == 'cpython' # via -r test-requirements.in @@ -79,7 +81,7 @@ markupsafe==3.0.2 # via jinja2 mccabe==0.7.0 # via pylint -mypy==1.14.1 +mypy==1.15.0 # via -r test-requirements.in mypy-extensions==1.0.0 # via @@ -90,7 +92,7 @@ nodeenv==1.9.1 # via # pre-commit # pyright -orjson==3.10.13 ; implementation_name == 'cpython' +orjson==3.10.15 ; implementation_name == 'cpython' # via -r test-requirements.in outcome==1.3.0.post0 # via -r test-requirements.in @@ -110,17 +112,17 @@ platformdirs==4.3.6 # virtualenv pluggy==1.5.0 # via pytest -pre-commit==4.0.1 +pre-commit==4.1.0 # via -r test-requirements.in pycparser==2.22 ; os_name == 'nt' or platform_python_implementation != 'PyPy' # via cffi -pygments==2.18.0 +pygments==2.19.1 # via sphinx -pylint==3.3.3 +pylint==3.3.4 # via -r test-requirements.in -pyopenssl==24.3.0 +pyopenssl==25.0.0 # via -r test-requirements.in -pyright==1.1.391 +pyright==1.1.393 # via -r test-requirements.in pytest==8.3.4 # via -r test-requirements.in @@ -128,7 +130,7 @@ pyyaml==6.0.2 # via pre-commit requests==2.32.3 # via sphinx -ruff==0.9.3 +ruff==0.9.6 # via -r test-requirements.in sniffio==1.3.1 # via -r test-requirements.in @@ -136,7 +138,9 @@ snowballstemmer==2.2.0 # via sphinx sortedcontainers==2.4.0 # via -r test-requirements.in -sphinx==7.4.7 +sphinx==7.4.7 ; python_full_version < '3.10' + # via -r test-requirements.in +sphinx==8.1.3 ; python_full_version >= '3.10' # via -r test-requirements.in sphinxcontrib-applehelp==2.0.0 # via sphinx @@ -169,7 +173,7 @@ types-docutils==0.21.0.20241128 # via -r test-requirements.in types-pyopenssl==24.1.0.20240722 # via -r test-requirements.in -types-setuptools==75.6.0.20241223 +types-setuptools==75.8.0.20250210 # via types-cffi typing-extensions==4.12.2 # via @@ -178,12 +182,13 @@ typing-extensions==4.12.2 # black # mypy # pylint + # pyopenssl # pyright urllib3==2.3.0 # via requests -uv==0.5.24 +uv==0.5.30 # via -r test-requirements.in -virtualenv==20.28.0 +virtualenv==20.29.2 # via pre-commit zipp==3.21.0 ; python_full_version < '3.10' # via importlib-metadata