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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With