How can I know if a Python module exists, without importing it?
Importing something that might not exist (not what I want) results in:
try:
import eggs
except ImportError:
pass
TL;DR) Use importlib.util.find_spec(module_name) (Python 3.4+).
Python2: imp.find_module
To check if import can find something in Python 2, using imp:
import imp
try:
imp.find_module('eggs')
found = True
except ImportError:
found = False
To find dotted imports, you need to do more:
import imp
try:
spam_info = imp.find_module('spam')
spam = imp.load_module('spam', *spam_info)
imp.find_module('eggs', spam.__path__) # __path__ is already a list
found = True
except ImportError:
found = False
You can also use pkgutil.find_loader (more or less the same as the Python 3 part:
import pkgutil
eggs_loader = pkgutil.find_loader('eggs')
found = eggs_loader is not None
Python 3
Python 3 ≤ 3.3: importlib.find_loader
You should use importlib. I went about doing this like:
import importlib
spam_loader = importlib.find_loader('spam')
found = spam_loader is not None
My expectation being, if you can find a loader for it, then it exists. You can also be a bit more smart about it, like filtering out what loaders you will accept. For example:
import importlib
spam_loader = importlib.find_loader('spam')
# only accept it as valid if there is a source file for the module - no bytecode only.
found = issubclass(type(spam_loader), importlib.machinery.SourceFileLoader)
Python 3 ≥ 3.4: importlib.util.find_spec
In Python 3.4 importlib.find_loader Python documentation was deprecated in favour of importlib.util.find_spec. The recommended method is the importlib.util.find_spec. There are others like importlib.machinery.FileFinder, which is useful if you're after a specific file to load. Figuring out how to use them is beyond the scope of this.
import importlib
spam_spec = importlib.util.find_spec("spam")
found = spam_spec is not None
This also works with relative imports, but you must supply the starting package, so you could also do:
import importlib
spam_spec = importlib.util.find_spec("..spam", package="eggs.bar")
found = spam_spec is not None
spam_spec.name == "eggs.spam"
While I'm sure there exists a reason for doing this - I'm not sure what it would be.
Warning
When trying to find a submodule, it will import the parent module (for ALL of the above methods)!
food/
|- __init__.py
|- eggs.py
## __init__.py
print("module food loaded")
## eggs.py
print("module eggs")
were you then to run
>>> import importlib
>>> spam_spec = importlib.util.find_spec("food.eggs")
module food loaded
ModuleSpec(name='food.eggs', loader=<_frozen_importlib.SourceFileLoader object at 0x10221df28>, origin='/home/user/food/eggs.py')
Comments are welcome on getting around this
Acknowledgements
#rvighne for importlib
#lucas-guido for Python 3.3+ deprecating find_loader
#enpenax for pkgutils.find_loader behaviour in Python 2.7
Python 3 >= 3.6: ModuleNotFoundError
The ModuleNotFoundError has been introduced in Python 3.6 and can be used for this purpose:
try:
import eggs
except ModuleNotFoundError:
# Error handling
pass
The error is raised when a module or one of its parents cannot be found. So
try:
import eggs.sub
except ModuleNotFoundError as err:
# Error handling
print(err)
would print a message that looks like No module named 'eggs' if the eggs module cannot be found; but it would print something like No module named 'eggs.sub' if only the sub module couldn't be found, but the eggs package could be found.
See the documentation of the import system for more information on the ModuleNotFoundError.
After using yarbelk's response, I've made this so I don't have to import ìmp.
try:
__import__('imp').find_module('eggs')
# Make things with a supposed existing module
except ImportError:
pass
It is useful in Django's settings.py file, for example.
Python 2, without relying on ImportError
Until the current answer is updated, here is the way for Python 2
import pkgutil
import importlib
if pkgutil.find_loader(mod) is not None:
return importlib.import_module(mod)
return None
Why another answer?
A lot of answers make use of catching an ImportError. The problem with that is, that we cannot know what throws the ImportError.
If you import your existent module and there happens to be an ImportError in your module (e.g., typo on line 1), the result will be that your module does not exist.
It will take you quite the amount of backtracking to figure out that your module exists and the ImportError is caught and makes things fail silently.
go_as's answer as a one-liner:
python -c "help('modules');" | grep module
Use one of the functions from pkgutil, for example:
from pkgutil import iter_modules
def module_exists(module_name):
return module_name in (name for loader, name, ispkg in iter_modules())
I wrote this helper function:
def is_module_available(module_name):
if sys.version_info < (3, 0):
# python 2
import importlib
torch_loader = importlib.find_loader(module_name)
elif sys.version_info <= (3, 3):
# python 3.0 to 3.3
import pkgutil
torch_loader = pkgutil.find_loader(module_name)
elif sys.version_info >= (3, 4):
# python 3.4 and above
import importlib
torch_loader = importlib.util.find_spec(module_name)
return torch_loader is not None
Here is a way to check if a module is loaded from the command line:
Linux/UNIX script file method: make a file module_help.py:
#!/usr/bin/env python
help('modules')
Then make sure it's executable: chmod u+x module_help.py
And call it with a pipe to grep:
./module_help.py | grep module_name
Invoke the built-in help system. (This function is intended for interactive use.) If no argument is given, the interactive help system starts on the interpreter console. If the argument is a string, then the string is looked up as the name of a module, function, class, method, keyword, or documentation topic, and a help page is printed on the console. If the argument is any other kind of object, a help page on the object is generated.
Interactive method: in the console, load python
>>> help('module_name')
If found, quit reading by typing q.
To exit the Python interpreter interactive session, press Ctrl + D
Windows script file method, also Linux/UNIX compatible, and better overall:
#!/usr/bin/env python
import sys
help(sys.argv[1])
Calling it from the command like:
python module_help.py site
Would output:
Help on module site:
NAME
site - Append module search paths for third-party packages to sys.path.
FILE
/usr/lib/python2.7/site.py
MODULE DOCS
http://docs.python.org/library/site
DESCRIPTION
...
:
And you'd have to press q to exit interactive mode.
Using it for an unknown module, e.g.,
python module_help.py lkajshdflkahsodf
Would output:
no Python documentation found for 'lkajshdflkahsodf'
and exit.
You could just write a little script that would try to import all the modules and tell you which ones are failing and which ones are working:
import pip
if __name__ == '__main__':
for package in pip.get_installed_distributions():
pack_string = str(package).split(" ")[0]
try:
if __import__(pack_string.lower()):
print(pack_string + " loaded successfully")
except Exception as e:
print(pack_string + " failed with error code: {}".format(e))
Output:
zope.interface loaded successfully
zope.deprecation loaded successfully
yarg loaded successfully
xlrd loaded successfully
WMI loaded successfully
Werkzeug loaded successfully
WebOb loaded successfully
virtualenv loaded successfully
...
A word of warning: this will try to import everything, so you'll see things like PyYAML failed with error code: No module named pyyaml, because the actual import name is just yaml. So as long as you know your imports, this should do the trick for you.
There isn't any way to reliably check if "dotted module" is importable without importing its parent package. Saying this, there are many solutions to problem "how to check if a Python module exists".
The below solution addresses the problem that an imported module can raise an ImportError even if it exists. We want to distinguish that situation from such in which the module does not exist.
Python 2:
import importlib
import pkgutil
import sys
def find_module(full_module_name):
"""
Returns module object if module `full_module_name` can be imported.
Returns None if module does not exist.
Exception is raised if (existing) module raises exception during its import.
"""
module = sys.modules.get(full_module_name)
if module is None:
module_path_tail = full_module_name.split('.')
module_path_head = []
loader = True
while module_path_tail and loader:
module_path_head.append(module_path_tail.pop(0))
module_name = ".".join(module_path_head)
loader = bool(pkgutil.find_loader(module_name))
if not loader:
# Double check if module realy does not exist
# (case: full_module_name == 'paste.deploy')
try:
importlib.import_module(module_name)
except ImportError:
pass
else:
loader = True
if loader:
module = importlib.import_module(full_module_name)
return module
Python 3:
import importlib
def find_module(full_module_name):
"""
Returns module object if module `full_module_name` can be imported.
Returns None if module does not exist.
Exception is raised if (existing) module raises exception during its import.
"""
try:
return importlib.import_module(full_module_name)
except ImportError as exc:
if not (full_module_name + '.').startswith(exc.name + '.'):
raise
In django.utils.module_loading.module_has_submodule:
import sys
import os
import imp
def module_has_submodule(package, module_name):
"""
check module in package
django.utils.module_loading.module_has_submodule
"""
name = ".".join([package.__name__, module_name])
try:
# None indicates a cached miss; see mark_miss() in Python/import.c.
return sys.modules[name] is not None
except KeyError:
pass
try:
package_path = package.__path__ # No __path__, then not a package.
except AttributeError:
# Since the remainder of this function assumes that we're dealing with
# a package (module with a __path__), so if it's not, then bail here.
return False
for finder in sys.meta_path:
if finder.find_module(name, package_path):
return True
for entry in package_path:
try:
# Try the cached finder.
finder = sys.path_importer_cache[entry]
if finder is None:
# Implicit import machinery should be used.
try:
file_, _, _ = imp.find_module(module_name, [entry])
if file_:
file_.close()
return True
except ImportError:
continue
# Else see if the finder knows of a loader.
elif finder.find_module(name):
return True
else:
continue
except KeyError:
# No cached finder, so try and make one.
for hook in sys.path_hooks:
try:
finder = hook(entry)
# XXX Could cache in sys.path_importer_cache
if finder.find_module(name):
return True
else:
# Once a finder is found, stop the search.
break
except ImportError:
# Continue the search for a finder.
continue
else:
# No finder found.
# Try the implicit import machinery if searching a directory.
if os.path.isdir(entry):
try:
file_, _, _ = imp.find_module(module_name, [entry])
if file_:
file_.close()
return True
except ImportError:
pass
# XXX Could insert None or NullImporter
else:
# Exhausted the search, so the module cannot be found.
return False
In case you know the location of file and want to check that the respective Python code file has that module or not, you can simply check via the astor package in Python. Here is a quick example:
"""
Check if a module function exists or not without importing a Python package file
"""
import ast
import astor
tree = astor.parse_file('handler.py')
method_to_check = 'handle'
for item in tree.body:
if isinstance(item, ast.FunctionDef):
if item.name == method_to_check:
print('method exists')
break
A simpler if statement from Ask Ubuntu, How do I check whether a module is installed in Python?:
import sys
print('eggs' in sys.modules)
You can also use importlib.util directly
import importlib.util
def module_exists_without_import(module_name):
spec = importlib.util.find_spec(module_name)
return spec is not None
import v_framework as framework
framework.loadModules(["Maintenance"])
framework.Maintenance.showPage()
In framework I have:
def loadModules(aModules):
d_utility = {"Maintenance":"COOl_M_PAGE"}
for module in a_aModules:
exec("import " + d_utility[module] + " as " + module)
When loadModules is executed, it imports the modules in the v_framework namespace. Since I am importing v_framework as framework, I think I should be able to use the imported module using framework.Maintenance. But it does not work that way.
Is there a way to do way to do what I'm trying to do? Alternatively, is there any way to import modules in a namespace other than the one where exec is executed?
There are libraries for importing modules dynamically. You could use importlib (and another one that might be useful is pkgutil). Now, for your case, I guess this would do the job:
import importlib
mods = {}
def loadModules(aModule):
global mods
mods[module] = importlib.import_module(d_utility[module])
# or maybe globals()[module] = ... would work also (exactly as you expect it to
UPDATE: exec modifies the function's local namespace, not the global one (I think).
Hope it helps. :)
When you import inside a function, the module is imported/executed as normal, but the name you import under is local to the function, just like any other variable assigned inside a function.
>>> def test_import():
... import os
... print os
...
>>> test_import()
<module 'os' from '/usr/lib/python2.7/os.pyc'>
>>> os
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
os has been imported though, and you can still access it through sys.modules:
>>> import sys
>>> sys.modules['os']
<module 'os' from '/usr/lib/python2.7/os.pyc'>
>>> os = sys.modules['os']
>>> os
<module 'os' from '/usr/lib/python2.7/os.pyc'>
A quick and dirty way to do what you want would be something like this; exec takes an optional mapping to be used as the local and global variables. So you could do
def loadModules(aModules):
d_utility = {"Maintenance":"COOl_M_PAGE"}
for module in aModules:
exec ('import %s as %s' % (d_utility[module], module)) in globals()
Though this is ugly and probably has security implications or something. As jadkik94 mentions, there are libraries that provide cleaner ways to deal with this.
I used to think that once a module was loaded, no re-importing would be done if other files imported that same module, or if it were imported in different ways. For example, I have mdir/__init__.py, which is empty, and mdir/mymod.py, which is:
thenum = None
def setNum(n):
global thenum
if thenum is not None:
raise ValueError("Num already set")
thenum = n
def getNum():
if thenum is None:
raise ValueError("Num hasn't been set")
return thenum
First few use cases from the same file go according to expectation. This file is ./usage.py, the same folder mdir is in:
import mdir.mymod
mdir.mymod.setNum(4)
print mdir.mymod.getNum()
from mdir import mymod
print mymod.getNum()
from mdir.mymod import *
print getNum()
try:
setNum(10)
except ValueError:
print "YHep, exception"
The output is as expected:
4
4
4
YHep, exception
However, if I muck with the system path, then it looks like the module is imported anew:
#BEHOLD
import sys
sys.path.append("mdir")
import mymod
try:
mymod.getNum()
except ValueError:
print "Should not have gotten exception"
mymod.setNum(10)
print mymod.getNum()
print mdir.mymod.getNum()
That code, running after the previous code, yields:
Should not have gotten exception
10
4
What gives?
mymod and mdir.mymod are considered different modules - here's somewhat related discussion: http://code.djangoproject.com/ticket/3951
Explanation:
It's best to play with python interactive interpreter and see for yourself. I created directory (package) mydir under some directory and inside it two files (modules) - __init__.py and mymod.py, both empty. I started python inside of directory containing mydir. Now see what happens:
>>> import mydir.mymod
>>> from mydir import mymod
>>> mymod == mydir.mymod
True
Why are mymod and mydir.mymod considered the same thing? Well, both names refer to the same module object - modules equality is determined by their paths comparison:
>>> mymod
<module 'mydir.mymod' from 'mydir\mymod.py'>
>>> mydir.mymod
<module 'mydir.mymod' from 'mydir\mymod.py'>
Now, if I alter sys.path to contain mydir and import mymod in such a way that path of imported module will seem to be different:
>>> import sys
>>> sys.path.append( "d:/zrodla/stack/mydir" )
# note that importing mymod (and not mydir.mymod) prior to appending mydir to
# path would cause an error
>>> mymod2
<module 'mymod' from 'd:/zrodla/stack/mydir\mymod.pyc'>
>>> mymod2 == mydir.mymod
False
then resulting module objects will not compare equal. This way one module will be imported twice - it's normal and that's the way python works. Just remember that imported modules are identified by their paths - more specifically by 'dotted paths' I think - look at sys.modules keys:
>>> [x for x in sys.modules.keys() if "my" in x]
['mydir', 'mymod', 'mydir.mymod']
I hope it's clear now.
I'm having trouble with the following code:
def get_module(mod_path):
mod_list = mod_path.split('.')
mod = __import__(mod_list.pop(0))
while mod_list:
mod = getattr(mod, mod_list.pop(0))
return mod
When I do get_module('qmbpmn.common.db_parsers') I get the error message:
AttributeError: 'module' object has no attribute 'db_parsers'.
However: import qmbpmn.common.db_parsers works perfectly fine.
When using __import__ to import submodules, you must pass the parent package as the fromlist argument:
>>> __import__("os.path")
<module 'os' from '/usr/lib/python2.6/os.pyc'>
>>> __import__("os.path", fromlist=["os"])
<module 'posixpath' from '/usr/lib/python2.6/posixpath.pyc'>
__import__ works with the dotted module path, so this should work
def get_module(mod_path):
return __import__(mod_path)
or more simply
get_module = __import__
Perhaps I am misunderstanding the problem
importing a package does not automatically import all the submodules into it's namespace. For example
import qmbpmn
does not mean that
qmbpmn.common.db_parsers
will automatically resolve
I'm working on a django project that serves multiple sites; depending on the site I want to import different functionality from a different module; how do I import a module in Python if I have the name of its package and the module name itself as a string?
in Python generally, you can use __import__ builtin function or imp module features:
>>> sys1 = __import__("sys")
>>> import imp
>>> sys2 = imp.load_module("sys2", *imp.find_module("sys"))
>>> import sys
>>> sys is sys1 is sys2
True
Django has its own import function to get an objet from a string. From documentation:
django.utils.module_loading
Functions for working with Python modules.
import_string(dotted_path)
Imports a dotted module path and returns the attribute/class designated by the last name in the path. Raises ImportError if the import failed. For example:
from django.utils.module_loading import import_string
ValidationError = import_string('django.core.exceptions.ValidationError')
is equivalent to:
from django.core.exceptions import ValidationError