Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Friendlier error messages on import for missing modules

I want to implement some friendlier error messages if the user tries to run a python script which tries to import modules that have not been installed. This includes printing out instructions on how to install the missing module.

One way to do this would be to put a try..catch block around the imports, but this is a bit ugly since it would turn something simple like

import some_module

into

try:
  import some_module
except ImportError, e:
  handle_error(e)

and it would have to be added to every file. Additionally, ImportError doesn't seem to store the name of the missing module anywhere (except for in the message) so you would have to put a separate try..catch around each import if you need to know the name (like I do). Parsing the name of the module is not the option since the message carried by ImportError might change for python version to version and depending on the user's locale.

I guess I could use sys.excepthook to catch all exceptions and pass those except ImportError along. Or would it be possible to define something like

safe_import some_module

that would behave like I want?

Does anyone know of any existing solutions to this problem?

like image 983
pafcu Avatar asked Oct 24 '09 18:10

pafcu


2 Answers

You can put, somewhere that it will always be executed (e.g. in site.py or sitecustomize.py):

import __builtin__

realimport = __builtin__.__import__

def myimport(modname, *a):
  try:
    return realimport(modname, *a)
  except ImportError, e:
    print "Oops, couldn't import %s (%s)" % (modname, e)
    print "Here: add nice directions and whatever else"
    raise

__builtin__.__import__ = myimport

See the __import__ docs here.

like image 103
Alex Martelli Avatar answered Nov 15 '22 00:11

Alex Martelli


You don't have to catch ImportError for every import. You can use a global try..except block in the entry point of your script.

You can get the name of the missing module from a ImportError instance using the message property.

For example, if the entry point of your script is main.py:

if __name__ == '__main__':
    try:
        import module1
        import module2

        module1.main()
     except ImportError as error:
        print "You don't have module {0} installed".format(error.message[16:])

Don't import anything outside the try..except block. This will cover module1 and module2 and all the modules imported by them and so on.

As you said, you could define your own import_safe function:

def import_safe(module):
    try:
        return __import__(module)
    except ImportError as error:
        print "You don't have module {0} installed".format(error.message[16:])

Then you can use the function:

sys = import_safe('sys')
gtk = import_safe('gkt')

In my opinion, the fist strategy is better. The second one would make your code hard to read. And will change an essential part of the language.

like image 32
Manuel Ceron Avatar answered Nov 14 '22 23:11

Manuel Ceron