diff --git a/docs/source/history.rst b/docs/source/history.rst index 6d69d28dc4..56f7112da6 100644 --- a/docs/source/history.rst +++ b/docs/source/history.rst @@ -5,6 +5,24 @@ Release history .. towncrier release notes start +Trio 0.24.0 (2024-01-10) +------------------------ + +Features +~~~~~~~~ + +- New helper classes: :class:`~.testing.RaisesGroup` and :class:`~.testing.Matcher`. + + In preparation for changing the default of ``strict_exception_groups`` to `True`, we're introducing a set of helper classes that can be used in place of `pytest.raises `_ in tests, to check for an expected `ExceptionGroup`. + These are provisional, and only planned to be supplied until there's a good solution in ``pytest``. See https://github.com/pytest-dev/pytest/issues/11538 (`#2785 `__) + + +Deprecations and removals +~~~~~~~~~~~~~~~~~~~~~~~~~ + +- ``MultiError`` has been fully removed, and all relevant trio functions now raise ExceptionGroups instead. This should not affect end users that have transitioned to using ``except*`` or catching ExceptionGroup/BaseExceptionGroup. (`#2891 `__) + + Trio 0.23.2 (2023-12-14) ------------------------ diff --git a/newsfragments/2785.feature.rst b/newsfragments/2785.feature.rst deleted file mode 100644 index 8dff767e4b..0000000000 --- a/newsfragments/2785.feature.rst +++ /dev/null @@ -1,4 +0,0 @@ -New helper classes: :class:`~.testing.RaisesGroup` and :class:`~.testing.Matcher`. - -In preparation for changing the default of ``strict_exception_groups`` to `True`, we're introducing a set of helper classes that can be used in place of `pytest.raises `_ in tests, to check for an expected `ExceptionGroup`. -These are provisional, and only planned to be supplied until there's a good solution in ``pytest``. See https://github.com/pytest-dev/pytest/issues/11538 diff --git a/newsfragments/2891.deprecated.rst b/newsfragments/2891.deprecated.rst deleted file mode 100644 index 59dba79360..0000000000 --- a/newsfragments/2891.deprecated.rst +++ /dev/null @@ -1 +0,0 @@ -``MultiError`` has been fully removed, and all relevant trio functions now raise ExceptionGroups instead. This should not affect end users that have transitioned to using ``except*`` or catching ExceptionGroup/BaseExceptionGroup. diff --git a/src/trio/_subprocess.py b/src/trio/_subprocess.py index 26eecc796b..37513380f3 100644 --- a/src/trio/_subprocess.py +++ b/src/trio/_subprocess.py @@ -11,9 +11,7 @@ import trio -from ._abc import AsyncResource, ReceiveStream, SendStream from ._core import ClosedResourceError, TaskStatus -from ._deprecate import deprecated from ._highlevel_generic import StapledStream from ._subprocess_platform import ( create_pipe_from_child_output, @@ -28,7 +26,9 @@ from collections.abc import Awaitable, Callable, Mapping, Sequence from io import TextIOWrapper - from typing_extensions import Self, TypeAlias + from typing_extensions import TypeAlias + + from ._abc import ReceiveStream, SendStream # Sphinx cannot parse the stringified version @@ -101,7 +101,7 @@ def fileno(self) -> int: @final -class Process(AsyncResource, metaclass=NoPublicConstructor): +class Process(metaclass=NoPublicConstructor): r"""A child process. Like :class:`subprocess.Popen`, but async. This class has no public constructor. The most common way to get a @@ -223,41 +223,6 @@ def returncode(self) -> int | None: self._close_pidfd() return result - @deprecated( - "0.20.0", - thing="using trio.Process as an async context manager", - issue=1104, - instead="run_process or nursery.start(run_process, ...)", - ) - async def __aenter__(self) -> Self: - return self - - # Type ignore is for `Type of decorated function contains type "Any" ("Callable[[Process], Coroutine[Any, Any, None]]")` - @deprecated( - "0.20.0", issue=1104, instead="run_process or nursery.start(run_process, ...)" - ) - async def aclose(self) -> None: # type: ignore[misc] - """Close any pipes we have to the process (both input and output) - and wait for it to exit. - - If cancelled, kills the process and waits for it to finish - exiting before propagating the cancellation. - """ - with trio.CancelScope(shield=True): - if self.stdin is not None: - await self.stdin.aclose() - if self.stdout is not None: - await self.stdout.aclose() - if self.stderr is not None: - await self.stderr.aclose() - try: - await self.wait() - finally: - if self._proc.returncode is None: - self.kill() - with trio.CancelScope(shield=True): - await self.wait() - def _close_pidfd(self) -> None: if self._pidfd is not None: trio.lowlevel.notify_closing(self._pidfd.fileno()) diff --git a/src/trio/_tests/test_deprecate.py b/src/trio/_tests/test_deprecate.py index efacb27b3a..48130e66f1 100644 --- a/src/trio/_tests/test_deprecate.py +++ b/src/trio/_tests/test_deprecate.py @@ -260,32 +260,3 @@ def test_module_with_deprecations(recwarn_always: pytest.WarningsRecorder) -> No with pytest.raises(AttributeError): module_with_deprecations.asdf # type: ignore[attr-defined] # noqa: B018 # "useless expression" - - -def test_tests_is_deprecated1() -> None: - with pytest.warns(TrioDeprecationWarning): - from trio import tests # warning on import - - # warning on access of any member - with pytest.warns(TrioDeprecationWarning): - assert tests.test_abc # type: ignore[attr-defined] - - -def test_tests_is_deprecated2() -> None: - # warning on direct import of test since that accesses `__spec__` - with pytest.warns(TrioDeprecationWarning): - import trio.tests - - with pytest.warns(TrioDeprecationWarning): - assert trio.tests.test_deprecate # type: ignore[attr-defined] - - -def test_tests_is_deprecated3() -> None: - import trio - - # no warning on accessing the submodule - assert trio.tests - - # only when accessing a submodule member - with pytest.warns(TrioDeprecationWarning): - assert trio.tests.test_abc # type: ignore[attr-defined] diff --git a/src/trio/_tests/test_subprocess.py b/src/trio/_tests/test_subprocess.py index d2bf39d42d..976180ab22 100644 --- a/src/trio/_tests/test_subprocess.py +++ b/src/trio/_tests/test_subprocess.py @@ -22,7 +22,6 @@ import pytest from .. import ( - ClosedResourceError, Event, Process, _core, @@ -168,38 +167,6 @@ async def test_multi_wait(background_process: BackgroundProcessType) -> None: proc.kill() -# Test for deprecated 'async with process:' semantics -async def test_async_with_basics_deprecated(recwarn: pytest.WarningsRecorder) -> None: - async with await open_process( - CAT, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE - ) as proc: - pass - assert proc.returncode is not None - assert proc.stdin is not None - assert proc.stdout is not None - assert proc.stderr is not None - with pytest.raises(ClosedResourceError): - await proc.stdin.send_all(b"x") - with pytest.raises(ClosedResourceError): - await proc.stdout.receive_some() - with pytest.raises(ClosedResourceError): - await proc.stderr.receive_some() - - -# Test for deprecated 'async with process:' semantics -async def test_kill_when_context_cancelled(recwarn: pytest.WarningsRecorder) -> None: - with move_on_after(100) as scope: - async with await open_process(SLEEP(10)) as proc: - assert proc.poll() is None - scope.cancel() - await sleep_forever() - assert scope.cancelled_caught - assert got_signal(proc, SIGKILL) - assert repr(proc) == "".format( - SLEEP(10), "exited with signal 9" if posix else "exited with status 1" - ) - - COPY_STDIN_TO_STDOUT_AND_BACKWARD_TO_STDERR = python( "data = sys.stdin.buffer.read(); " "sys.stdout.buffer.write(data); " diff --git a/src/trio/_version.py b/src/trio/_version.py index 517db31018..a7b8d6f0fe 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.23.2+dev" +__version__ = "0.24.0+dev" diff --git a/src/trio/tests.py b/src/trio/tests.py deleted file mode 100644 index 1c5f039f0f..0000000000 --- a/src/trio/tests.py +++ /dev/null @@ -1,40 +0,0 @@ -import importlib -import sys -from typing import Any - -from . import _tests -from ._deprecate import warn_deprecated - -warn_deprecated( - "trio.tests", - "0.22.1", - instead="trio._tests", - issue=274, -) - - -# This won't give deprecation warning on import, but will give a warning on use of any -# attribute in tests, and static analysis tools will also not see any content inside. -class TestsDeprecationWrapper: - """trio.tests is deprecated, use trio._tests""" - - __name__ = "trio.tests" - - def __getattr__(self, attr: str) -> Any: - warn_deprecated( - f"trio.tests.{attr}", - "0.22.1", - instead=f"trio._tests.{attr}", - issue=274, - ) - - # needed to access e.g. trio._tests.tools, although pytest doesn't need it - if not hasattr(_tests, attr): # pragma: no cover - importlib.import_module(f"trio._tests.{attr}", "trio._tests") - return attr - - return getattr(_tests, attr) - - -# https://stackoverflow.com/questions/2447353/getattr-on-a-module -sys.modules[__name__] = TestsDeprecationWrapper() # type: ignore[assignment]