Skip to content

Conversation

@AbduazizZiyodov
Copy link
Member

@AbduazizZiyodov AbduazizZiyodov commented Sep 23, 2025

Closes #3326 by deprecating both testing.RaisesGroup and testing.Matcher where pytest alternative recommended from now on..

Replaced existing test cases with pytest alternatives.

@AbduazizZiyodov
Copy link
Member Author

AbduazizZiyodov commented Sep 23, 2025

I've got couple of questions.

  • Version should be 0.31.0 or 0.32.0 ?
  • Is that OK to warn about deprecation during __init__ or do I have to move this into __enter__ ?
  • What can we do about the existing tests that uses RaisesGroup, can just "replace" them with pytest alternative ?
image

(I'll include newsfragment later)

@codecov
Copy link

codecov bot commented Sep 23, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00000%. Comparing base (b178251) to head (ba44d3c).

Additional details and impacted files
@@               Coverage Diff               @@
##                 main        #3337   +/-   ##
===============================================
  Coverage   100.00000%   100.00000%           
===============================================
  Files             128          128           
  Lines           19407        19405    -2     
  Branches         1318         1318           
===============================================
- Hits            19407        19405    -2     
Files with missing lines Coverage Δ
src/trio/_core/_tests/test_cancelled.py 100.00000% <100.00000%> (ø)
src/trio/_core/_tests/test_ki.py 100.00000% <100.00000%> (ø)
src/trio/_core/_tests/test_parking_lot.py 100.00000% <100.00000%> (ø)
src/trio/_core/_tests/test_run.py 100.00000% <100.00000%> (ø)
src/trio/_deprecate.py 100.00000% <100.00000%> (ø)
src/trio/_tests/test_channel.py 100.00000% <100.00000%> (ø)
src/trio/_tests/test_exports.py 100.00000% <100.00000%> (ø)
src/trio/_tests/test_highlevel_open_tcp_stream.py 100.00000% <100.00000%> (ø)
src/trio/_tests/test_highlevel_serve_listeners.py 100.00000% <100.00000%> (ø)
src/trio/_tests/test_signals.py 100.00000% <100.00000%> (ø)
... and 7 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@A5rocks
Copy link
Contributor

A5rocks commented Sep 23, 2025

I've got couple of questions.

  • version should be the next Trio version. Since we're including a deprecation, this is a "minor" change, it's 0.32.0.
  • personally I think this should warn on attribute access! See _deprecate.deprecate_attributes. This way, someone even just going trio.RaisesGroup would get the warning without having to initialize it
  • yeah. I think the idiomatic replacement is pytest.raises_group? (Maybe the deprecation should link that instead of the class)

@AbduazizZiyodov
Copy link
Member Author

@A5rocks

personally I think this should warn on attribute access! See _deprecate.deprecate_attributes. This way, someone even just going trio.RaisesGroup would get the warning without having to initialize it

Makes sense. However even if I deprecate it on trio/__init__.py like this:

_deprecate.deprecate_attributes(
    __name__,
    {
        "RaisesGroup": _deprecate.DeprecatedAttribute(
            "RaisesGroup",
            version="0.32.0",
            issue=3326,
            instead="See https://docs.pytest.org/en/stable/reference/reference.html#pytest.RaisesGroup",
        )
    },
)

On trio.testing.RaisesGroup or just using RaisesGroup (via from trio.testing import) won't show any warnings. I guess we're trying to warn on even occurrence of RaisesGroup (even tried on testing/__init__.py). Am I missing something ? Thanks.

@A5rocks
Copy link
Contributor

A5rocks commented Sep 23, 2025

I think the deprecation should go in trio.testing?

I'm probably misunderstanding what you're saying cause it sounds like you tried that...

@A5rocks
Copy link
Contributor

A5rocks commented Sep 23, 2025

Note that this is how the usage looks like (it's a bit complicated because you need the actual underlying object, but under a different name)

deprecate_attributes(__name__, {
    "RaisesGroup": DeprecatedAttribute(_RaisesGroup, "0.32.0", ...)
})

Copy link
Contributor

@A5rocks A5rocks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just putting in an actual review because GitHub keeps wanting me to see this. Previous comments still apply!

@jakkdl
Copy link
Member

jakkdl commented Oct 27, 2025

note that Matcher (and AbstractMatcher I suppose) also needs to be deprecated. The tests that test RaisesGroup/Matcher itself should suppress the deprecation warning, while all other tests that make use of them should be updated to use the equivalent ones in pytest.

@AbduazizZiyodov
Copy link
Member Author

@jakkdl

  1. Regarding to Matcher:
    with RaisesGroup(
        Matcher(_core.BrokenResourceError, match="^Parking lot broken by"),
    ):
        async with _core.open_nursery() as nursery:
            nursery.start_soon(bad_parker, lot, cs)
            await wait_all_tasks_blocked()

            nursery.start_soon(lot.park)
            await wait_all_tasks_blocked()

            cs.cancel()

How should I supposed to write this via pytest alternatives, specifically Matcher ? We can't pass Matcher to pytest.RaisesGroup as I see. I did search for Matcher from pytest docs, however I'm not sure whether it does same job.

  1. Should we suppress warnings (for the modules/files that actually test trio's RaisesGroup as you mentioned) like this (in pyproject.toml):
[tool.pytest.ini_options]
filterwarnings = [
  # ...
  'ignore::trio.TrioDeprecationWarning:trio._tests.test_testing_raisesgroup'
]

From my point of view, files that should suppress deprecations are:

  • trio._tests.test_testing_raisesgroup.py
  • trio._tests.type_tests.raisesgroup.py ?

Anything else ?

@A5rocks
Copy link
Contributor

A5rocks commented Nov 3, 2025

@AbduazizZiyodov I might be misunderstanding things but:

  1. maybe just deprecate it? we don't need to provide a direct translation to pytest. (I think the direct translation is RaisesExc, though)
  2. suppress warnings per test case. I think there's examples elsewhere for how to apply a warning filter on a specific test case.

@jakkdl
Copy link
Member

jakkdl commented Nov 8, 2025

  1. yeah for tests that make use of Matcher outside those files the correct replacement is RaisesExc. It got renamed when moved to pytest.

@A5rocks
Copy link
Contributor

A5rocks commented Dec 4, 2025

@AbduazizZiyodov just bumping since it would be nice to get this by the next release. (which will be... I don't know yet, maybe New Year's would be a nice time?)

@AbduazizZiyodov
Copy link
Member Author

AbduazizZiyodov commented Dec 4, 2025

@A5rocks Yep, we can do that (till new year's).

@AbduazizZiyodov
Copy link
Member Author

AbduazizZiyodov commented Dec 25, 2025

@A5rocks @jakkdl Hi!

  • Deprecated both RaisesGroup and Matcher (but not AbstractMatcher which mentioned, shall we ?)
  • Deprecation warnings are suppressed on test cases that test RaisesGroup and Matcher. You might check pyproject.toml
  • Made DeprecatedAttribute class as final because of this (test case was failing)
  • Replaced existing test cases with pytest alternatives (pytest.RaisesGroup and pytest.RaisesExc)

Tried with minimal reproducer whether it works:

image

All tests were passing locally:

image

Suggestion: rename the title of issue & PR (I'll do myself)

edit: there was one merge conflict, it is fixed -- needs to be checked.

Thanks.

@AbduazizZiyodov AbduazizZiyodov changed the title Deprecate RaisesGroup Deprecate testing.RaisesGroup and testing.Matcher Dec 25, 2025
@AbduazizZiyodov
Copy link
Member Author

I guess ... CI is failing because of this, because attribute access emits deprecation warning.

Should we suppress warning on this test case or just remove the portion of the code ?

@A5rocks
Copy link
Contributor

A5rocks commented Dec 25, 2025

I guess ... CI is failing because of this, because attribute access emits deprecation warning.

Should we suppress warning on this test case or just remove the portion of the code ?

Why does that trigger a deprecation? That seems to only do stuff for trio.socket, based on a quick read.

@AbduazizZiyodov
Copy link
Member Author

I guess ... CI is failing because of this, because attribute access emits deprecation warning.
Should we suppress warning on this test case or just remove the portion of the code ?

Why does that trigger a deprecation? That seems to only do stuff for trio.socket, based on a quick read.

My bad, wrong link. Correct one:

if class_ is trio.testing.RaisesGroup or class_ is trio.testing.Matcher:

@A5rocks
Copy link
Contributor

A5rocks commented Dec 25, 2025

IMO check the qualname (or name) of the class then.

@AbduazizZiyodov
Copy link
Member Author

IMO check the qualname (or name) of the class then.

Something like this if class_name in ("RaisesGroup", "Matcher"): continue ?

@A5rocks
Copy link
Contributor

A5rocks commented Dec 26, 2025

Yeah plus a check on module name I guess.

@AbduazizZiyodov
Copy link
Member Author

Its done. But ...

FAILED ../../../../../../opt/hostedtoolcache/Python/3.14.2/x64-freethreaded/lib/python3.14t/site-packages/trio/_tests/test_exports.py::test_static_tool_sees_all_symbols[pyright_verifytypes-trio.testing] - AssertionError
FAILED ../../../../../../opt/hostedtoolcache/Python/3.14.2/x64-freethreaded/lib/python3.14t/site-packages/trio/_tests/test_exports.py::test_static_tool_sees_class_members[jedi-trio.testing] - AssertionError: assert not {'trio.testing.DeprecatedAttribute': {'extra': {'instead', 'issue', 'value', 'version'}, 'missing': set()}}
FAILED ../../../../../../opt/hostedtoolcache/Python/3.14.2/x64-freethreaded/lib/python3.14t/site-packages/trio/_tests/test_exports.py::test_static_tool_sees_class_members[mypy-trio.testing] - AssertionError: assert not {'trio.testing.DeprecatedAttribute': {'extra': {'instead', 'issue', 'value', 'version'}, 'missing': set()}, 'trio.testing._Matcher': {'extra': {'check', 'exception_type', 'match'}, 'missing': set()}, 'trio.testing._RaisesGroup': {'extra': {'allow_unwrapped', 'check', 'excinfo', 'expected_exceptions', 'flatten_subgroups', 'is_baseexceptiongroup', ...}, 'missing': set()}}

Copy link
Contributor

@A5rocks A5rocks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly just nitpicks. Thanks for the PR!

# to be reimplemented in pytest).
# Not 100% that's the case, and it works locally, so whatever /shrug
if module_name == "trio.testing" and class_name in ("RaisesGroup", "Matcher"):
if module_name == "trio.testing" and class_name in ("_RaisesGroup", "_Matcher"):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to add underscore prefix to match the convention used in exports (testing/__init__.py). This fixed test cases, except "type tests".

I tried to fix these also, you might check the diff (produced locally):
diff --git a/src/trio/_tests/test_testing_raisesgroup.py b/src/trio/_tests/test_testing_raisesgroup.py
index 9cc92993..4b6f787e 100644
--- a/src/trio/_tests/test_testing_raisesgroup.py
+++ b/src/trio/_tests/test_testing_raisesgroup.py
@@ -7,7 +7,7 @@ from types import TracebackType
 import pytest
 
 import trio
-from trio.testing import Matcher, RaisesGroup
+from trio.testing import _Matcher as Matcher, _RaisesGroup as RaisesGroup
 from trio.testing._raises_group import repr_callable
 
 if sys.version_info < (3, 11):
@@ -1107,7 +1107,7 @@ def test__ExceptionInfo(monkeypatch: pytest.MonkeyPatch) -> None:
         "ExceptionInfo",
         trio.testing._raises_group._ExceptionInfo,
     )
-    with trio.testing.RaisesGroup(ValueError) as excinfo:
+    with RaisesGroup(ValueError) as excinfo:
         raise ExceptionGroup("", (ValueError("hello"),))
     assert excinfo.type is ExceptionGroup
     assert excinfo.value.exceptions[0].args == ("hello",)
diff --git a/src/trio/_tests/test_util.py b/src/trio/_tests/test_util.py
index 69310d64..c8beefa1 100644
--- a/src/trio/_tests/test_util.py
+++ b/src/trio/_tests/test_util.py
@@ -9,7 +9,7 @@ if TYPE_CHECKING:
 import pytest
 
 import trio
-from trio.testing import Matcher, RaisesGroup
+from trio.testing import _Matcher as Matcher, _RaisesGroup as RaisesGroup
 
 from .. import _core
 from .._core._tests.tutil import (
diff --git a/src/trio/_tests/type_tests/raisesgroup.py b/src/trio/_tests/type_tests/raisesgroup.py
index 012c42b4..86c758ec 100644
--- a/src/trio/_tests/type_tests/raisesgroup.py
+++ b/src/trio/_tests/type_tests/raisesgroup.py
@@ -3,7 +3,7 @@ from __future__ import annotations
 import sys
 from collections.abc import Callable
 
-from trio.testing import Matcher, RaisesGroup
+from trio.testing import _Matcher as Matcher, _RaisesGroup as RaisesGroup
 from typing_extensions import assert_type
 
 if sys.version_info < (3, 11):
Which are basically import errors, but again pyright still "screaming":
❯ tox -m check
.pkg: _optional_hooks> python /home/abduaziz/Projects/OSS/trio/.venv/lib/python3.13/site-packages/pyproject_api/_backend.py True setuptools.build_meta
.pkg: get_requires_for_build_wheel> python /home/abduaziz/Projects/OSS/trio/.venv/lib/python3.13/site-packages/pyproject_api/_backend.py True setuptools.build_meta
.pkg: build_wheel> python /home/abduaziz/Projects/OSS/trio/.venv/lib/python3.13/site-packages/pyproject_api/_backend.py True setuptools.build_meta
gen_exports: install_package> python -I -m pip install --force-reinstall --no-deps /home/abduaziz/Projects/OSS/trio/.tox/.tmp/package/33/trio-0.32.0+dev-py3-none-any.whl
gen_exports: commands[0]> python ./src/trio/_tools/gen_exports.py --test
Scanning: /home/abduaziz/Projects/OSS/trio/src/trio/_core/_run.py
Scanning: /home/abduaziz/Projects/OSS/trio/src/trio/_core/_instrumentation.py
Scanning: /home/abduaziz/Projects/OSS/trio/src/trio/_core/_io_windows.py
Scanning: /home/abduaziz/Projects/OSS/trio/src/trio/_core/_io_epoll.py
Scanning: /home/abduaziz/Projects/OSS/trio/src/trio/_core/_io_kqueue.py
Generated sources are up to date.
gen_exports: OK ✔ in 2.69 seconds
pip_compile: install_package> python -I -m pip install --force-reinstall --no-deps /home/abduaziz/Projects/OSS/trio/.tox/.tmp/package/34/trio-0.32.0+dev-py3-none-any.whl
pip_compile: commands[0]> pre-commit run pip-compile --all-files
uv pip-compile test-requirements.in......................................Passed
uv pip-compile docs-requirements.in......................................Passed
pip_compile: OK ✔ in 1 second
typing: install_package> python -I -m pip install --force-reinstall --no-deps /home/abduaziz/Projects/OSS/trio/.tox/.tmp/package/35/trio-0.32.0+dev-py3-none-any.whl
typing: commands[0]> mypy --platform linux
Success: no issues found in 148 source files
typing: commands[1]> mypy --platform darwin
Success: no issues found in 148 source files
typing: commands[2]> mypy --platform win32
Success: no issues found in 148 source files
typing: commands[3]> pyright src/trio/_tests/type_tests
/home/abduaziz/Projects/OSS/trio/src/trio/_tests/type_tests/raisesgroup.py
  /home/abduaziz/Projects/OSS/trio/src/trio/_tests/type_tests/raisesgroup.py:6:26 - error: "_Matcher" is private and used outside of the module in which it is declared (reportPrivateUsage)
  /home/abduaziz/Projects/OSS/trio/src/trio/_tests/type_tests/raisesgroup.py:6:47 - error: "_RaisesGroup" is private and used outside of the module in which it is declared (reportPrivateUsage)
2 errors, 0 warnings, 0 informations
typing: exit 1 (1.54 seconds) /home/abduaziz/Projects/OSS/trio> pyright src/trio/_tests/type_tests pid=34297
typing: FAIL ✖ in 36.66 seconds
type_completeness: install_package> python -I -m pip install --force-reinstall --no-deps /home/abduaziz/Projects/OSS/trio/.tox/.tmp/package/36/trio-0.32.0+dev-py3-none-any.whl
type_completeness: commands[0]> python src/trio/_tests/check_type_completeness.py
********************
Checking Linux...
Congratulations, you have resolved existing errors! Please remove them from /home/abduaziz/Projects/OSS/trio/src/trio/_tests/_check_type_completeness.json, either manually or with '--overwrite-file'.
['No docstring found for function "trio.testing._raises_group._ExceptionInfo.exconly"', 'No docstring found for function "trio.testing._raises_group._ExceptionInfo.errisinstance"', 'No docstring found for function "trio.testing._raises_group._ExceptionInfo.getrepr"', 'No docstring found for function "trio.testing._raises_group.RaisesGroup.expected_type"']
********************
Checking Windows...
********************
Checking Darwin...
Congratulations, you have resolved existing errors! Please remove them from /home/abduaziz/Projects/OSS/trio/src/trio/_tests/_check_type_completeness.json, either manually or with '--overwrite-file'.
['No docstring found for function "trio.testing._raises_group._ExceptionInfo.exconly"', 'No docstring found for function "trio.testing._raises_group._ExceptionInfo.errisinstance"', 'No docstring found for function "trio.testing._raises_group._ExceptionInfo.getrepr"', 'No docstring found for function "trio.testing._raises_group.RaisesGroup.expected_type"']
********************
Congratulations, you have resolved existing errors! Please remove them from /home/abduaziz/Projects/OSS/trio/src/trio/_tests/_check_type_completeness.json, either manually or with '--overwrite-file'.
['No docstring found for function "trio.testing._raises_group._ExceptionInfo.exconly"', 'No docstring found for function "trio.testing._raises_group._ExceptionInfo.errisinstance"', 'No docstring found for function "trio.testing._raises_group._ExceptionInfo.getrepr"', 'No docstring found for function "trio.testing._raises_group.RaisesGroup.expected_type"']
type_completeness: exit 1 (5.14 seconds) /home/abduaziz/Projects/OSS/trio> python src/trio/_tests/check_type_completeness.py pid=34335
  gen_exports: OK (2.69=setup[1.49]+cmd[1.20] seconds)
  pip_compile: OK (1.00=setup[0.70]+cmd[0.29] seconds)
  typing: FAIL code 1 (36.66=setup[0.70]+cmd[11.40,11.34,11.68,1.54] seconds)
  type_completeness: FAIL code 1 (5.86=setup[0.71]+cmd[5.14] seconds)
  evaluation failed :( (46.28 seconds)

My concern is that am I in right direction ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO either delete the type tests or place a pyright: ignore on the imports.

The pyright type completeness thing is different

Copy link
Member Author

@AbduazizZiyodov AbduazizZiyodov Dec 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done ( removed type test & fixed mypy error(s) ).

Shall I modify _check_type_completeness.json too ? (as specified in failed job)

EDIT: I modified it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace trio.testing.RaisesGroup with pytest.RaisesGroup and trio.testing.Matcher with pytest.RaisesExc

3 participants