1

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 Answers3

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")
tripleee
  • 175,061
  • 34
  • 275
  • 318
0

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.

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 !

Nephty
  • 140
  • 1
  • 7