-
-
Notifications
You must be signed in to change notification settings - Fork 31.7k
Change in behavior when overriding warnings.showwarning and with catch_warnings(record=True) #73021
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
Comments
In Python 3.5, the following code: import warnings
def deal_with_warning(*args, **kwargs):
print("warning emitted")
with warnings.catch_warnings(record=True):
warnings.showwarning = deal_with_warning
warnings.warn("This is a warning") results in "warning emitted" being printed to the terminal. In Python 3.6 however (at least in 3.6b1), nothing is printed, meaning that https://bugs.python.org/issue26568 However it doesn't look like this was an intentional change in behavior, since it says in the description of that issue: "For backward compatibility, warnings.showmsg() calls warnings.showwarning() if warnings.showwarning() was replaced. Same for warnings.formatmsg(): call warnings.formatwarning() if replaced." So I believe this is a bug? (since backward-compatibility is not preserved). If not, should the change in behavior be mentioned in the changelog? |
It seems like a regression of Python 3.6, probably introduced by myself with add addition of warnings._showwarningmsg() and the source parameter. |
What's the status of this issue? It's currently blocking 360rc1. We either need a resolution now or defer it to 3.6.1. |
Ok, here is a fix. |
Oops, I made a mistake just before producing the patch: here is the right patch, test_warnings pass. |
Serhiy: Would you mind to review warnings_fix-2.patch? I tagged this bug as a release blocker, since it's a regression introduced in 3.6. |
Carefully reviewed, and tests are passing, issue is fixed: LGTM. |
Patch version 3: fix test_warnings when running the test with python3 -Werror. Reset filters in the new unit test. |
+1 from me as well |
The patch looks sensible to me. The fix is basically an extension to the first fixup (9c92352324e8), where Victor split _showwarnmsg_impl() out of _showwarnmsg(). Now, _showwarnmsg() is a helper for the C module to choose between the backwards-compatible showwarning() API, and the new internal _showwarnmsg_impl() function. I left some incidental comments on Rietveld, but they are not severe release blockers. Also, is the docstring for warnings._showwarnmsg() off? It looks like you copied it from warnings.showwarning(). Best not to suggest replacing an internal function. |
Actually, I found a regression. Looks like you also need to cancel any showwarning() function set by the user: >>> import warnings
>>> warnings.showwarning = print
>>> with warnings.catch_warnings(record=True) as recording:
... warnings.warn("hi") # Unpatched did not call print()
...
hi <class 'UserWarning'> __main__ 2 None None
>>> recording # Unpatched returned the warning here
[] Also, should the documentation of catch_warnings() be amended to say that there is no longer a custom showwarning() function? The recording mechanism is now an internal detail, and not accessible by calling showwarning(). |
I don't understand why test_showwarnmsg_missing was added. Why deleting warnings._showwarnmsg should be supported? I would rename _showwarning to _showwarning_orig for accenting it's purpose. It is used only for checking if showwarning was replaced by the user. |
New changeset 150d36dbe3ba by Victor Stinner in branch '3.6': |
I pushed a more complete version of my patch: New changeset 726308cfe3b5 by Victor Stinner in branch '3.6': I dislike pushing a different change than the reviewed change, but I was in a hurry for the Python 3.6.0 release :-/ Sorry about that. Please double-check the pushed change! (I used the wrong issue number, fixed in the following commit.) The final change also fixes the bug reported by Martin: Martin: "Actually, I found a regression. Looks like you also need to cancel any showwarning() function set by the user:" I fixed it in catch_warnings() with these lines: # Reset showwarning() to the default implementation to make sure
# that _showwarnmsg() calls _showwarnmsg_impl()
self._module.showwarning = self._module._showwarning It also added a new unit test for this scenario. Serhiy Storchaka: "I don't understand why test_showwarnmsg_missing was added. Why deleting warnings._showwarnmsg should be supported?" I don't know well the warnings module. The interactions between the C _warnings module and the Python warnings module are complex. I didn't want to break the backward compatibility, and *technically*, it is possible to delete warnings.showwarning() and warnings.warn("msg") still writes the message into stderr! So I decided to support this corner case, for the backward compatibility. Code: import warnings
warnings.warn("with showwarning")
del warnings.showwarning
warnings.warn("without showwarning") Output on Python 3.5 (before my showarnmsg() changes): Hum, but maybe we should decorate test_showwarnmsg_missing() with @cpython_only to announce that it's a side effect of the implementation, it's not part of the "Python specification". Serhiy Storchaka: "I would rename _showwarning to _showwarning_orig for accenting it's purpose. It is used only for checking if showwarning was replaced by the user." Sorry, I suck at naming things :-) Feel free to rename it (after the 3.6.0 release). By the way, I'm still interested to make showwarnmsg() public in Python 3.7. IMO it's interesting to give access to the new source parameter to custom warning loggers. And it will allow to more easily extend warnings with new parameters (it was the whole purpose of the issue bpo-26568). I keep the issue open so someone can still review the pushed change. |
Julien reviewed the pushed change and asked me questions on IRC:
|
Here is a patch that cleans up the code. |
Serhiy's patch LGTM. |
New changeset aaee06743c61 by Ned Deily in branch '3.6': New changeset 7bca3bf6401a by Ned Deily in branch 'default': |
Thanks everyone for getting this resolved for 360rc1! |
There's also issue bpo-28835 which might be related. |
Brett, msg282646 ? |
I just happened to look at that bug before seeing this bug and both mentioned recording issues so I thought I would mention there was a chance of a connection. |
Brett, what was the other bug? The bug number you posted is for this bug. |
If the intended reference was to bpo-28897, then yes, it was related: NumPy had introduced a workaround for the regression that existed in the beta releases (presumably thinking it was an intentional change that just hadn't been added to the porting guide yet), and this fix for the regression broke their workaround. Reverting the workaround on the NumPy side restored compatibility :) |
Misc/NEWS
so that it is managed by towncrier #552Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: