Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accept generic ExceptionGroups for raises #13134

Merged
merged 4 commits into from
Jan 24, 2025
Merged

Conversation

tapetersen
Copy link
Contributor

@tapetersen tapetersen commented Jan 14, 2025

Accept (Base)ExceptionGroup with generic arguments in pytest.raises

Closes #13115

  • Include documentation when adding new features.
  • Include new tests or update existing tests when applicable.
  • Allow maintainers to push and squash when merging my commits. Please uncheck this if you prefer to squash the commits yourself.

If this change fixes an issue, please:

  • Add text like closes #XYZW to the PR description and/or commits (where XYZW is the issue number). See the github docs for more information.

Unless your change is trivial or a small documentation fix (e.g., a typo or reword of a small section) please:

  • Create a new changelog file in the changelog folder, with a name like <ISSUE NUMBER>.<TYPE>.rst. See changelog/README.rst for details.

    Write sentences in the past or present tense, examples:

    • Improved verbose diff output with sequences.
    • Terminal summary statistics now use multiple colors.

    Also make sure to end the sentence with a ..

  • Add yourself to AUTHORS in alphabetical order.

@tapetersen tapetersen marked this pull request as draft January 15, 2025 11:00
@tapetersen tapetersen changed the title WIP: Accept generic ExceptionGroups for raises Accept generic ExceptionGroups for raises Jan 15, 2025
@psf-chronographer psf-chronographer bot added the bot:chronographer:provided (automation) changelog entry is part of PR label Jan 15, 2025
@tapetersen tapetersen marked this pull request as ready for review January 15, 2025 11:22
Copy link
Member

@Zac-HD Zac-HD left a comment

Choose a reason for hiding this comment

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

Nice work Tobias - and thanks for your first Pytest PR! I've left two minor comments below; once those are handled I expect we'll be able to merge 🎉

Comment on lines 982 to 985
if issubclass(origin_exc, ExceptionGroup) and exc_type is Exception:
return cast(type[E], origin_exc)
elif (
issubclass(origin_exc, BaseExceptionGroup) and exc_type is BaseException
Copy link
Member

Choose a reason for hiding this comment

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

I'd be inclined to do ... exc_type in (Any, (Base)Exception): here - the escape-hatch is particularly useful when you might want to do something specific with the contents later.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, fixed in patch (left as own commit I assume you'll squash)

changelog/13115.improvement.rst Outdated Show resolved Hide resolved
@tapetersen tapetersen force-pushed the main branch 2 times, most recently from c2a9b93 to a74e557 Compare January 20, 2025 18:06
Copy link
Member

@Zac-HD Zac-HD left a comment

Choose a reason for hiding this comment

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

Looks good to me, thanks again!

I'll merge later this week if no other maintainers have a review.

@tapetersen
Copy link
Contributor Author

Thanks for the review and consideration.

Copy link
Member

@nicoddemus nicoddemus left a comment

Choose a reason for hiding this comment

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

Thanks @tapetersen for the contribution!

I took the liberty of pushing some small changes that I noticed while testing this locally.

Let's please squash this when getting around to merge it. 👍

src/_pytest/python_api.py Show resolved Hide resolved
@tapetersen
Copy link
Contributor Author

tapetersen commented Jan 21, 2025

Thanks @tapetersen for the contribution!

I took the liberty of pushing some small changes that I noticed while testing this locally.

Let's please squash this when getting around to merge it. 👍

Ahh yes the traceback machinery you have I forgot about. If you find other things feel free to fix them directly and I do appreciate reading about why.

if isinstance(expected_exception, type):
expected_exceptions: tuple[type[E], ...] = (expected_exception,)
expected_exceptions = (expected_exception,)
Copy link

Choose a reason for hiding this comment

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

why comma is here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Without a comma it's not a tuple but just a singular value.

Python 3.10.12 (main, Jan 17 2025, 14:35:34) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> (1)
1
>>> (1,)
(1,)
>>> 

The original code had the same pattern.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In fact it's the parenthesis that are superfluous for everything except when creating the empty tuple

>>> 1,
(1,)

if issubclass(origin_exc, ExceptionGroup) and exc_type in (Exception, Any):
return cast(type[E], origin_exc)
elif issubclass(origin_exc, BaseExceptionGroup) and exc_type in (
BaseException,
Copy link

Choose a reason for hiding this comment

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

it is duplicate

Copy link
Contributor Author

@tapetersen tapetersen Jan 22, 2025

Choose a reason for hiding this comment

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

I'm not sure if your're refering to the if clauses (which are both needed) or that the action is the same.
If the latter, yes it could be refactored to a single clause with or if you think that's clearer (I tried both but especially after black formatting this looked clearer to me)

Copy link
Member

Choose a reason for hiding this comment

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

It is fine as is IMO.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tried the single clause variation again and I'm ok either way (the previous try was before I added the Any variation as well)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@nicoddemus Didn't see your comment before trying the alternative. Feel free to rebase and revert/keep as you want.

@Zac-HD Zac-HD merged commit ecff0ba into pytest-dev:main Jan 24, 2025
28 checks passed
@Zac-HD
Copy link
Member

Zac-HD commented Jan 24, 2025

Thanks again everyone! This will be a nice improvement for many people who like detailed static types 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bot:chronographer:provided (automation) changelog entry is part of PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Using Generic Exceptions (ExceptionGroups in particular) with raises in a type-safe manner is not ideal
4 participants