2

I have the following try block:

try: # depending on conditions, this can generate several types of errors mymodule.do_stuff() except Exception as e: print("something went wrong, the error was :" + type(e).__name__) 

I would like to catch potential errors from do_stuff(). After trial and error I was able to generate a list of potential errors that can be triggered by do_stuff() by printing their type(e).__name__ value:

DoStuffInsufficientMemoryException DoStuffInsufficientCPUException DoStuffInsufficientDiskException 

but if I try do modify my except statement from except Exception as e to except DoStuffInsufficientMemoryException, I will get the error that DoStuffInsufficientMemoryException is not defined.

I tried defining a class that extends Exception for it, as most tutorials / questions in here suggest, basically:

class WAFInvalidParameterException(Exception): pass 

so now that variable is recognized, but since I can't control the error that do_sutff() will raise, I can't really raise this exception in my initial try block.

Ideally I would like to have 1 except block for each error so I would like to have something like:

try: mymodule.do_stuff() except DoStuffInsufficientMemoryException: free_memory() except DoStuffInsufficientCPUException: kill_processes() except DoStuffInsufficientDiskException: free_disk_space() 

but of course this doesn't work as these variables are not defined.

3 Answers 3

2

Just like you can't reference do_stuff without its module specifier, you have to specify in which module namespace these exceptions are defined.

try: mymodule.do_stuff() except mymodule.DoStuffInsufficientMemoryException: free_memory() except mymodule.DoStuffInsufficientCPUException: kill_processes() except mymodule.DoStuffInsufficientDiskException: free_disk_space() 

If free_memory is also in the mymodule namespace, of course you need to specify it there as well.

Alternatively, when you import mymodule, you can explicitly import selected symbols into the current namespace:

from mymodule import do_stuff, DoStuffInsufficientMemoryException, ... 

and then, because they are in the current package, you can (or indeed must) refer to them without the package prefix mymodule.

A well-designed module will export selected symbols so you can refer to them without the package prefix, but whether this makes sense for your own package depends on its general design and intended audience. Some large packages define a separate subpackage for exceptions so you can say

import bigpackage.exceptions 

to import them all. You will probably still want to explore the package's documentation (or, if it's lacking, its source code) to discover which exceptions exist and how they are organized. Many packages define a base exception class from which all its other exceptions are subclasses so that you can easily catch them all with just one symbol, like

try: bigpackage.heavy_wizardry() except bigpackage.BigBaseException: print("you are turned into a frog") 
Sign up to request clarification or add additional context in comments.

Comments

1

Usually if a function

module.foo() 

throws an exception DoStuffInsufficientMemoryException it would be also importable as

from module import DoStuffInsufficientMemoryException 

If this results in ImportError then you need the fullname function from this answer; use it with e (it takes an instance and returns the class name). If it gives

foo.bar.DoStuffInsufficientMemoryException 

then you can import the exception as

from foo.bar import DoStuffInsufficientMemoryException 

The above might not work for all cases. One notable case is Boto 3 AWS client library that does not make the exceptions importable - instead they will be attributes on the client instance.

2 Comments

That's not what __qualname__ does - it's for classes and functions nested inside other classes or functions. (The most common case is methods.) For the module name, you want __module__.
@user2357112supportsMonica need more coffee. Fixed
0

EDIT : you can import other methods instead of creating your own, of course

The try/except block will try to execute the code and if an error is raised and specified in the except statement, it will stop the execution of the code located in the try block and execute the other code located in the except block. So, to catch your custom error, you have to raise it in the first place.

If you didn't know, you can raise errors using the raise statement. Here, I've made a simple chunk of code. I have a custom error, a variable x initialized at 2, and a method that adds 1 to the variable given in argument. The method will raise a CustomError if the variable becomes 3.

# Here, I define the custom error and allow a custom message to be displayed # using the super() method class CustomError(Exception): def __init__(self, msg): super().__init__(msg) # I initialize x at 2 x = 2 # I create the method that will add 1 to the variable given in argument # and raise a CustomError if the variable becomes 3 # This is completely random, and you can make whatever checks you want before raising # Your custom error def do_stuff(x): x += 1 if x == 3: raise CustomError("x is 3") # Now, I write the try/except block. I raise e (the CustomError) if it is # being raised in the method do_stuff(x) try: do_stuff(x) except CustomError as e: raise e 

Feel free to try the code out to get a better understanding of it !

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.