Tidier way of trying to import a module from multiple locations?
-
23-08-2019 - |
Question
Is there a way to tidy-up the following code, rather than a series of nested try/except statements?
try:
import simplejson as json
except ImportError:
try:
import json
except ImportError:
try:
from django.utils import simplejson as json
except:
raise "Requires either simplejson, Python 2.6 or django.utils!"
Solution
I found the following function at http://mail.python.org/pipermail/python-list/2007-May/441896.html. It seems to work quite well, and I'm pretty sure the way its importing won't stomp on any existing imports you might already have.
def module_exists(module_name):
try:
mod = __import__(module_name)
except ImportError:
return False
else:
return True
if module_exists('simplejson'):
import simplejson as json
elif module_exists('json'):
import json
elif module_exists('django.utils'):
from django.utils import simplejson as json
else:
raise ImportError('Requires either simplejson, Python 2.6 or django.utils')
I know this seems like more code, but the function is reusable elsewhere if you're doing a lot of this.
OTHER TIPS
def import_any(*mod_list):
res = None
for mod in mod_list:
try:
res = __import__(mod)
return res
except ImportError:
pass
raise ImportError("Requires one of " + ', '.join(mod_list))
json = import_any('simplejson', 'json', 'django.utils.simplejson')
I appreciate the pretty functions for doing this, but the pattern you illustrate in the original question is the most commonly used pattern for this requirement. You can see it used in many open source projects.
I suggest you stick with it. Remember "ugly" is not always "bad".
This avoids the nesting, but I'm not sure it is any better :)
json = None
if json is None:
try:
import json
except ImportError:
pass
if json is None:
try:
import simplejson as json
except ImportError:
pass
if json is None:
try:
from django.utils import simplejson as json
except ImportError:
pass
if json is None:
raise ImportError('Requires either simplejson, Python 2.6 or django.utils')
I've come up with a simple alternative that doesn't rely on defining functions:
# Create a dummy enclosing
while True:
try:
import simplejson as json
break
except:
pass
try:
import json
break
except:
pass
try:
from django.utils import simplejson as json
break
except:
pass
raise ImportError('Requires either simplejson, Python 2.6 or django.utils')
Note, I'm not entirely sure whether it's prettier than the approach using the helper function.