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

pytest.warns multiple argument handling #11917

Closed
wants to merge 6 commits into from

Conversation

reaganjlee
Copy link
Contributor

Fixes #11906

w.message.__class__, # type: ignore[arg-type]
w.filename,
w.lineno,
message=w.message, # type: ignore[arg-type]
Copy link
Member

Choose a reason for hiding this comment

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

The docs say:

message must be a string and category a subclass of Warning or message may be a Warning instance, in which case category will be ignored.

So I think this should be:

Suggested change
message=w.message, # type: ignore[arg-type]
message=w,

No?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

w is of type warnings.WarningMessage, which isn't a Warning instance whereas w.message is.

I added this above this line to check

print(f"type(w) is: {type(w)}") # <class 'warnings.WarningMessage'>
print(f"type(w) is subclass of Warning: {issubclass(type(w), Warning)}") # False
print(f"type(w.message) is: {type(w.message)}") # <class 'test_recwarn.TestWarns.test_multiple_arg_custom_warning.<locals>.CustomWarning'>
print(f"type(w.message) is subclass of Warning: {issubclass(type(w.message), Warning)}") # True

Copy link
Member

Choose a reason for hiding this comment

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

Indeed, sorry for the confusion.

So if I understand things correctly, WarningMessage.message can be either a message str or a full Warning, hence the arg-type mypy error. BUT, the old code seems to have assumed that w.message is always a Warning, so maybe it's true here. Still, maybe it'd be safer to appease mypy and write it like this:

if isinstance(w.message, Warning):
    message: Union[Warning, str] = w.message
    category: Optional[Type[Warning]] = None
else:
    message = w.message
    category = w.category
warnings.warn_explicit(
    message,
    category,
    ...
)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes that makes sense!

Copy link
Contributor Author

@reaganjlee reaganjlee Feb 6, 2024

Choose a reason for hiding this comment

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

Hm, I'm having a bit of trouble with the mypy and the requirements for warn_explicit() (without just type ignoring). Would you mind taking a look?

Copy link
Member

Choose a reason for hiding this comment

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

After trying it and reading the warn_explicit code, I think we should be good with just this:

                        message=w.message,
                        category=w.category,

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.

LGTM!

Left a small suggest, other than that we also need a changelog, please create changelog/11906.bugfix.rst with something along these lines:

Fix regression using :func:`pytest.warns` with custom warning subclasses which have more than one parameter in their `__init__`.

@@ -477,3 +477,14 @@ def test_catch_warning_within_raise(self) -> None:
with pytest.raises(ValueError, match="some exception"):
warnings.warn("some warning", category=FutureWarning)
raise ValueError("some exception")

def test_multiple_arg_custom_warning(self) -> None:
Copy link
Member

Choose a reason for hiding this comment

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

Let's just add a docstring to mention the original issue for future reference (I know we can eventually find it via git-blame, but often things move around, code is refactored/reformatted, so I think it pays to just slap the issue number along with the test):

Suggested change
def test_multiple_arg_custom_warning(self) -> None:
def test_multiple_arg_custom_warning(self) -> None:
"""pytest.warns with custom warning subclass with multiple arguments (#11906)."""

Copy link
Member

@bluetech bluetech left a comment

Choose a reason for hiding this comment

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

Thanks @reaganjlee!

@bluetech
Copy link
Member

bluetech commented Feb 8, 2024

@reaganjlee There is a conflict, can you rebase on latest main please?

implement @bluetech changes

implement code review changes
Copy link
Member

@bluetech bluetech left a comment

Choose a reason for hiding this comment

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

Left a question on the new change. Also there are some formatting changes which seem unnecessary so linting fails, can you remove them?

@@ -336,7 +332,9 @@ def found_str():

@staticmethod
def _validate_message(wrn: Any) -> None:
if not isinstance(msg := wrn.message.args[0], str):
Copy link
Member

Choose a reason for hiding this comment

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

Can you explain these changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After making the other changes, the code failed some tests from #11804 that solved #10865, where the incorrect arguments then defaulted to becoming UserWarnings. However, the implementation also caught the custom CustomWarning class (where wrn.message.args[0] = int from CustomWarning's __init__, which this looked to fix.
This looks related to #11954

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm, this looks like it could be its own PR potentially. Another implementation: #11959

@bluetech
Copy link
Member

Merged through #11991, thanks @reaganjlee!

@bluetech bluetech closed this Feb 16, 2024
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.

Bug in 8.0.0 pytest.warns handling
3 participants