Helper to show code to hide warnings
This is inspired by the [discussion on iterable strings](https://mail.python.org/archives/list/python-ideas@python.org/thread/WKEFHT4...), although I think it has applications elsewhere. Sometimes programs emit warnings that need to be filtered out. Maybe they're coming from dependencies that we don't control, or maybe it's our own code but it's a problem that can't be fixed or isn't worth the trouble. But filtering warnings correctly isn't very easy. You generally shouldn't ignore all warnings, as this would hide important ones. Similarly, you probably shouldn't even filter an entire category, which is what many end up doing. A good compromise is to specify both the category and the module. In particular this lets you ignore warnings from libraries while still being able to see warnings from your own code. But there are obstacles on the way: 1. Remembering the syntax is hard. I've never been able to. 2. Looking it up is hard. If I Google "python ignore warnings" the top result is a Stack Overflow question where neither the accepted answer nor the most upvoted answer mention specifying a module. The second Google result is the Python docs which are not easy to read through. 3. There's lots of similarly named methods and it's hard to find the right one. Is it catch_warnings, simplefilter, or filterwarnings? 4. When warnings are displayed, they show the filename, but filters require a module name, and converting between the two is tedious. 5. The more warnings there are, and thus the more serious the need to filter them properly, the more work it is to write all the filters. I propose we add a built in mechanism that is easy to use and remember which displays Python code that can be copy pasted. For example, this could be a configuration option which causes the line of code to be shown in stderr immediately after the actual warning. Alternatively, here's a context manager / decorator which prints the code after it exits: import inspect import warnings from contextlib import contextmanager import __main__ @contextmanager def showfilters(): with warnings.catch_warnings(record=True) as warnings_list: yield for warning in warnings_list: if warning.filename == getattr(__main__, "__file__", object()): module = "__main__" else: module = inspect.getmodulename(warning.filename) module = bool(module) * f", module={module!r}" print( f"warnings.filterwarnings('ignore', " f"category={warning.category.__name__}" f"{module})" ) # Sample usage # Prints the below, uncomment to confirm that output disappears # warnings.filterwarnings('ignore', category=UserWarning, module='__main__') # warnings.filterwarnings('ignore', category=SyntaxWarning) @showfilters() # comment out to see original warnings def main(): warnings.warn("DOOM") exec("assert (1, 2)") main() This is of course a rough implementation, there are probably things it does wrong and there's all sorts of details about the desired behaviour we could debate about. The aim is that the code it prints is good enough for most cases and can easily be edited, particularly by deleting lines. Does this seem like a good general idea?
2. Looking it up is hard. If I Google "python ignore warnings" the top result is a Stack Overflow question where neither the accepted answer nor the most upvoted answer mention specifying a module. The second Google result is the Python docs which are not easy to read through.
Hmm, I think we may benefit from focusing the efforts on this point (at least at first), particularly with regards to making the official documentation for the warnings module [1] easier to understand with some more examples, or perhaps writing a warnings HOWTO guide [2], which could include the correct way to add filters for specific warning types by module for a significant number of different filters. From my perspective, this seems to be more of an issue with a lack of understanding and clear guides for using the existing tools, rather than a direct indication that additional tools need to be added.
3. There's lots of similarly named methods and it's hard to find the right one. Is it catch_warnings, simplefilter, or filterwarnings?
While I agree that the names might be a bit similar, I personally find that the names accurately describe what each of them do, particularly `filterwarnings()` and `catch_warnings()`. The purpose of `simplefilter()` in relation to `filterwarnings()` might not be as obvious without reading the documentation, but I don't think there's much that can reasonably be done to address it. I also don't find it to be an especially significant concern.
4. When warnings are displayed, they show the filename, but filters require a module name, and converting between the two is tedious.
I could see it being useful to have a utility for filtering warnings by filename rather than just module, if it's reasonably possible to implement.
5. The more warnings there are, and thus the more serious the need to filter them properly, the more work it is to write all the filters.
This could be potentially addressed by adding an example in the warning docs or a new warnings HOWTO that includes something along the lines of the following: ``` modules_to_filter = {"foo": ResourceWarning, "bar": DeprecationWarning} for mod, cat in modules_to_filter.items(): warnings.filterwarnings("ignore", category=cat, module=mod) ``` (I suspect the actual documented example would be much more fleshed out and explained, the above was very quickly thrown together as a rough example) Alternatively, we could consider adding a helper function to the warnings module for adding a filter with the same action and warning category across multiple modules at once; by accepting a collection of a strings instead of a single string (like `filterwarnings()` does for it's *module* parameter). I'm not certain if the implementation would be too trivial to justify a new helper function for it, but the use case may be common enough for something like that to be reasonable.
I propose we add a built in mechanism that is easy to use and remember which displays Python code that can be copy pasted.
I really don't like the idea of a builtin that specifically revolves around the expectation of its output being copied and pasted as code elsewhere, particularly from an API design perspective. Also, *if* we were to consider something like this, it seems more appropriate to be included in the warnings module rather than as a builtin.
Does this seem like a good general idea?
-1 on the addition of the proposed builtin, but +1 on the general idea of making the process of correctly adding a decent volume of warning filters more clear. --- [1] - https://docs.python.org/3/library/warnings.html [2] - https://docs.python.org/3/howto/index.html On Tue, Feb 25, 2020 at 4:04 PM Alex Hall <alex.mojaki@gmail.com> wrote:
This is inspired by the [discussion on iterable strings]( https://mail.python.org/archives/list/python-ideas@python.org/thread/WKEFHT4...), although I think it has applications elsewhere.
Sometimes programs emit warnings that need to be filtered out. Maybe they're coming from dependencies that we don't control, or maybe it's our own code but it's a problem that can't be fixed or isn't worth the trouble.
But filtering warnings correctly isn't very easy. You generally shouldn't ignore all warnings, as this would hide important ones. Similarly, you probably shouldn't even filter an entire category, which is what many end up doing. A good compromise is to specify both the category and the module. In particular this lets you ignore warnings from libraries while still being able to see warnings from your own code. But there are obstacles on the way:
1. Remembering the syntax is hard. I've never been able to. 2. Looking it up is hard. If I Google "python ignore warnings" the top result is a Stack Overflow question where neither the accepted answer nor the most upvoted answer mention specifying a module. The second Google result is the Python docs which are not easy to read through. 3. There's lots of similarly named methods and it's hard to find the right one. Is it catch_warnings, simplefilter, or filterwarnings? 4. When warnings are displayed, they show the filename, but filters require a module name, and converting between the two is tedious. 5. The more warnings there are, and thus the more serious the need to filter them properly, the more work it is to write all the filters.
I propose we add a built in mechanism that is easy to use and remember which displays Python code that can be copy pasted. For example, this could be a configuration option which causes the line of code to be shown in stderr immediately after the actual warning. Alternatively, here's a context manager / decorator which prints the code after it exits:
import inspect import warnings from contextlib import contextmanager import __main__
@contextmanager def showfilters(): with warnings.catch_warnings(record=True) as warnings_list: yield
for warning in warnings_list: if warning.filename == getattr(__main__, "__file__", object()): module = "__main__" else: module = inspect.getmodulename(warning.filename) module = bool(module) * f", module={module!r}" print( f"warnings.filterwarnings('ignore', " f"category={warning.category.__name__}" f"{module})" )
# Sample usage # Prints the below, uncomment to confirm that output disappears # warnings.filterwarnings('ignore', category=UserWarning, module='__main__') # warnings.filterwarnings('ignore', category=SyntaxWarning)
@showfilters() # comment out to see original warnings def main(): warnings.warn("DOOM") exec("assert (1, 2)")
main()
This is of course a rough implementation, there are probably things it does wrong and there's all sorts of details about the desired behaviour we could debate about. The aim is that the code it prints is good enough for most cases and can easily be edited, particularly by deleting lines. Does this seem like a good general idea? _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/YGI6EJ... Code of Conduct: http://python.org/psf/codeofconduct/
Kyle Stanley wrote:
Hmm, I think we may benefit from focusing the efforts on this point (at least at first), particularly with regards to making the official documentation for the warnings module [1] easier to understand with some more examples, or perhaps writing a warnings HOWTO guide [2], which could include the correct way to add filters for specific warning types by module for a significant number of different filters.
Adding *more* documentation can easily make the problem worse in some ways. We're dealing with the very tricky problem of directing and sustaining attention.
When warnings are displayed, they show the filename, but filters require a module name, and converting between the two is tedious.
I could see it being useful to have a utility for filtering warnings by filename rather than just module, if it's reasonably possible to implement.
Filtering by an exact filename wouldn't work for code that's meant to run on multiple systems. Filtering by some kind of pattern could maybe work, but brings in new problems.
The more warnings there are, and thus the more serious the need to filter them properly, the more work it is to write all the filters.
This could be potentially addressed by adding an example in the warning docs or a new warnings HOWTO that includes something along the lines of the following: modules_to_filter = {"foo": ResourceWarning, "bar": DeprecationWarning} for mod, cat in modules_to_filter.items(): warnings.filterwarnings("ignore", category=cat, module=mod)
(I suspect the actual documented example would be much more fleshed out and explained, the above was very quickly thrown together as a rough example) Alternatively, we could consider adding a helper function to the warnings module for adding a filter with the same action and warning category across multiple modules at once; by accepting a collection of a strings instead of a single string (like filterwarnings() does for it's module parameter).
This doesn't really help. It's already easy to copy and paste `warnings.filterwarnings("ignore", module="", category=)` ten times. And people know how to write a loop. It's the process of extracting categories and module names that requires work either way.
I propose we add a built in mechanism that is easy to use and remember which displays Python code that can be copy pasted. I really don't like the idea of a builtin that specifically revolves around the expectation of its output being copied and pasted as code elsewhere, particularly from an API design perspective.
Can you elaborate on the problem? There's already catch_warnings to collect data.
Also, if we were to consider something like this, it seems more appropriate to be included in the warnings module rather than as a builtin.
Sorry, to clarify, by "built in mechanism" I meant any interface (not necessarily a function) that doesn't require installing an external tool. A function would definitely be in the warnings module.
+1 on the general idea of making the process of correctly adding a decent volume of warning filters more clear.
The problem here is not knowledge, it's effort. All these obstacles are not that hard to get past, but they make lazier choices more tempting. Most users will therefore either: 1. Not filter warnings at all, thus making it harder to notice genuinely important warnings. 2. Filter too many warnings because that's so much easier. This in turn can make API designers reluctant to add important warnings because of the potential impact on their users. At worst their users will be harmed by not seeing other important warnings. At best they will be annoyed either by constantly seeing warnings or by the effort of hiding them properly. I'm saying that the correct way to do things should be as easy and frictionless as possible, so that by default it's the first thing users want to do. Then warnings can become exactly as obtrusive as they're meant to be. A single function that can be found via autocomplete and requires no arguments is really easy, and calling it would be the hardest step.
Adding *more* documentation can easily make the problem worse in some ways. We're dealing with the very tricky problem of directing and sustaining attention.
This doesn't really help. It's already easy to copy and paste `warnings.filterwarnings("ignore", module="", category=)` ten times. And
Improving the existing docs doesn't necessarily mean adding more in terms to length or total content, even if an example or two were added. Often times a significant documentation improvement can result in less total characters. people know how to write a loop. It's the process of extracting categories and module names that requires work either way. I'm not arguing that the example covers anything remotely involved or complex, but based on your initial statement regarding it being hard to find out how to properly ignore by a specific warning category and module in general, it seemed like a step in the right direction.
Can you elaborate on the problem? There's already catch_warnings to
collect data.
There's a very large difference between relying on printing to stdout and copy pasting the text into code (in the initial implementation example) vs collecting the warnings to a log when a specific parameter is set to true. See https://github.com/python/cpython/blob/be7ead62db9a1db3e2cd997b0beffd4480e51.... It's not so much of an issue with it collecting warning data, but rather how it's being returned to the user.
Sorry, to clarify, by "built in mechanism" I meant any interface (not necessarily a function) that doesn't require installing an external tool. A function would definitely be in the warnings module.
Ah, I see. We typically refer to "built in" or "builtins" as specifically being a member of the "builtins" module (which includes the builtin functions and constants). A member that can be accessed without requiring the installation of any external tools would typically be referred to as a member of the standard library. Describing a member that can be accessed without external tools as a "built in mechanism" isn't really wrong since it's *effectively *a "built in mechanism" to CPython, but it might be a bit confusing though (particularly on here and python-dev). Regarding this proposal specifically, it's much easier to consider a new member for the warnings module than it is for builtins. :)
The problem here is not knowledge, it's effort. All these obstacles are not that hard to get past, but they make lazier choices more tempting
2. Looking it up is hard. If I Google "python ignore warnings" the top result is a Stack Overflow question where neither the accepted answer nor
This seems to somewhat contradict (2) in the OP though, no?: the most upvoted answer mention specifying a module. The second Google result is the Python docs which are not easy to read through. and potentially (3) as well. If one has already seen it or used it before, it's rather easy to navigate to "docs.python.org" => enter warnings module => skim through member names (alternatively, just "import warnings; dir(warnings)" if you forgot what it was called or "help(warnings)" for a quick summary). From my perspective at least, if someone has to rely on a generic google search for "python ignore warnings" and didn't know to look for the warnings module, there's a good chance they have have minimal knowledge and experience of working with warning filters. A HOWTO guide that focuses on different useful things you can do with the warnings module could help with this, and would be written intentionally as something to be "read through" (as opposed to the warnings module docs, which is a bit more intended as a technical reference manual). Also, as a sidenote, on my search engine for "python ignore warnings" I encountered https://stackoverflow.com/questions/14463277/how-to-disable-python-warnings just below the results for the warning module documentation, where the most upvoted answer included usage of `warnings.simplefilter()`, `warnings.filterwarnings()`, and `warnings.catch_warnings()`. It didn't mention module-specific warning filters, but there is mention of it in the comments below the answer.
I'm saying that the correct way to do things should be as easy and frictionless as possible, so that by default it's the first thing users want to do.
While I agree in general, with filtering out warnings specifically there's a fine balance. At some point, it becomes tempting to just ignore the warnings instead of addressing the actual issue (particularly when a removal version isn't specified or is more than 2 major versions away). This of course doesn't apply so much though if the warning is being emitted from a 3rd party library rather than your own code. Besides submitting a bug report or patch and waiting, there's not much to do on the user end other than temporarily filtering it. I think we already make it rather easy to do properly through `warnings.filterwarnings()` (as long as users are aware of it), so I think it's more of a concern of it being tedious when you have to explicitly specify each module to ignore a specific warning for. I'm in favor of making it easier to filter warnings the correct way rather than making it more tempting to put a massive blanket filter across all modules though. It's certainly a valid concern and I'm very much open to considering a means to address it, I just don't think the proposed solution in this thread would be the right way to address it; at least not so far. On Wed, Feb 26, 2020 at 3:47 AM Alex Hall <alex.mojaki@gmail.com> wrote:
Kyle Stanley wrote:
Hmm, I think we may benefit from focusing the efforts on this point (at least at first), particularly with regards to making the official documentation for the warnings module [1] easier to understand with some more examples, or perhaps writing a warnings HOWTO guide [2], which could include the correct way to add filters for specific warning types by module for a significant number of different filters.
Adding *more* documentation can easily make the problem worse in some ways. We're dealing with the very tricky problem of directing and sustaining attention.
When warnings are displayed, they show the filename, but filters require a module name, and converting between the two is tedious.
I could see it being useful to have a utility for filtering warnings by filename rather than just module, if it's reasonably possible to implement.
Filtering by an exact filename wouldn't work for code that's meant to run on multiple systems. Filtering by some kind of pattern could maybe work, but brings in new problems.
The more warnings there are, and thus the more serious the need to filter them properly, the more work it is to write all the filters.
This could be potentially addressed by adding an example in the warning docs or a new warnings HOWTO that includes something along the lines of the following: modules_to_filter = {"foo": ResourceWarning, "bar": DeprecationWarning} for mod, cat in modules_to_filter.items(): warnings.filterwarnings("ignore", category=cat, module=mod)
(I suspect the actual documented example would be much more fleshed out and explained, the above was very quickly thrown together as a rough example) Alternatively, we could consider adding a helper function to the warnings module for adding a filter with the same action and warning category across multiple modules at once; by accepting a collection of a strings instead of a single string (like filterwarnings() does for it's module parameter).
This doesn't really help. It's already easy to copy and paste `warnings.filterwarnings("ignore", module="", category=)` ten times. And people know how to write a loop. It's the process of extracting categories and module names that requires work either way.
I propose we add a built in mechanism that is easy to use and remember which displays Python code that can be copy pasted. I really don't like the idea of a builtin that specifically revolves around the expectation of its output being copied and pasted as code elsewhere, particularly from an API design perspective.
Can you elaborate on the problem? There's already catch_warnings to collect data.
Also, if we were to consider something like this, it seems more appropriate to be included in the warnings module rather than as a builtin.
Sorry, to clarify, by "built in mechanism" I meant any interface (not necessarily a function) that doesn't require installing an external tool. A function would definitely be in the warnings module.
+1 on the general idea of making the process of correctly adding a decent volume of warning filters more clear.
The problem here is not knowledge, it's effort. All these obstacles are not that hard to get past, but they make lazier choices more tempting. Most users will therefore either:
1. Not filter warnings at all, thus making it harder to notice genuinely important warnings. 2. Filter too many warnings because that's so much easier.
This in turn can make API designers reluctant to add important warnings because of the potential impact on their users. At worst their users will be harmed by not seeing other important warnings. At best they will be annoyed either by constantly seeing warnings or by the effort of hiding them properly.
I'm saying that the correct way to do things should be as easy and frictionless as possible, so that by default it's the first thing users want to do. Then warnings can become exactly as obtrusive as they're meant to be. A single function that can be found via autocomplete and requires no arguments is really easy, and calling it would be the hardest step. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/GEOE2S... Code of Conduct: http://python.org/psf/codeofconduct/
I'm still not clear on what the problem is with a function that prints code to be copy pasted. It should probably output to stderr rather than stdout, and maybe that can be configurable, but I don't think that's what your problem is. I think that even if you've filtered warnings before, it's hard to remember how and looking it up is still reasonably difficult and tedious. Solving this problem by improving documentation is a delicate art that's difficult to measure and easy to get wrong, and it can only improve the situation somewhat. I'm not against it, but someone has to volunteer to do it, and I'm expecting it's just not going to happen. On the other hand, the goal of this proposal is that once you've looked up the function once, you have a decent chance of remembering it without looking it up again. It could also be a primary target to attract user attention while browsing through documentation, making the lookup process easier. Yes, that was the stackoverflow question I was referring to, and I think that comment is too far down to be sufficiently noticeable. You can see from the comment upvotes that most people are very happy to filter an entire category and leave it at that.
While I agree in general
I think I'm missing something because in the rest of the paragraph it just sounds like you continue to agree with me in the specifics as well.
participants (2)
-
Alex Hall
-
Kyle Stanley