3

I have some code that's schematically along the lines of:

from logging import warning

def complex_function():
    # Do some stuff
    raise Warning("blah") 
    # Do some more stuff
    raise Warning("Blah again") 

try: 
    complex_function()
except Warning as e: 
    warning(e) 

This results in:

WARNING:root:blah

I would like to catch all warnings raised, and log them. In my code, such warnings sometimes come from 3rd party libraries, so it is not practical to modify the warnings in place to use logging.warning, and I also want to store the warning information so that I can return some version of that information via an API.

Is there a way for me to do something like this that catches all warnings, and loops over them?

edit

Too late, I'm realising that I'm raising warnings wrong in the example above, and complex_function should be something long the lines of:

def complex_function():
    # Do some stuff
    warnings.warn("blah") 
    # Do some more stuff
    warnings.warn("Blah again", UnknownWarningType)

And I think I can catch these with warnings.catch_warnings

naught101
  • 18,687
  • 19
  • 90
  • 138
  • 2
    https://docs.python.org/3/library/logging.html#logging.warning, perhaps? – DirtyBit Apr 03 '19 at 06:46
  • 1
    I think try catch will break at the first warning/error. You might want to take a look at this post: https://stackoverflow.com/questions/5644836/in-python-how-does-one-catch-warnings-as-if-they-were-exceptions/7207340 – Nasta Apr 03 '19 at 06:47
  • I guess you could `yield` warnings instead. – Peter Wood Apr 03 '19 at 06:49
  • @DirtyBit: Updated the question to clarify why that won't work for me. – naught101 Apr 03 '19 at 06:50
  • @Nasta: yes, that looks like it might work. If you want to ad an answer like that here, I could accept it. – naught101 Apr 03 '19 at 06:51
  • @PeterWood: I'm not sure what that means. I can't find anything relevant by searching for those two words together... – naught101 Apr 03 '19 at 06:54
  • 1
    Aren't the Warnings meant to break the flow of execution? If not, you shouldn't be raising them. You could pass a list as a parameter to fill with warnings, or return a list of warnings. – Peter Wood Apr 03 '19 at 07:07
  • 1
    You're right, @PeterWood, I was forgetting about the difference between raising and calling `warnings.warn`. I added a clarification, and I will close the question. Sorry for the wild goose chase, and thanks for the help. – naught101 Apr 03 '19 at 22:42

1 Answers1

3

Were you expecting something like the following:

import warnings
warnings.filterwarnings('error')


def warning_func():
    print('hello')
    warnings.warn(Warning('Warn1'))
    print('hi')
    warnings.warn(Warning('Warn2'))


with warnings.catch_warnings(record=True) as w:
    warnings.simplefilter("always")
    warning_func()
    print(w)
Jeril
  • 7,858
  • 3
  • 52
  • 69
  • No. That only captures the first exception, same as my example in the question. – naught101 Apr 03 '19 at 06:53
  • Can you once check the revised solution please. – Jeril Apr 03 '19 at 07:00
  • I don't think it will work, because I don't necessarily know what type the warning will be - it might be a `RuntimeWarning` from numpy, or it might be something else entirely. – naught101 Apr 03 '19 at 22:14
  • Coming back to this, this seems to work exactly as I needed. I don't think you need the `Warning()` inside the `warnings.warn()` though - just a message is enough. And I can't figure out what the `warnings.simplefilter` is doing - it doesn't work without it, but the functions docs don't really indicate why... – naught101 Apr 19 '19 at 06:54