How to check if a Python module exists without importing it

python, python-import

Solution

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.util
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.util
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

Problem

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 ```

Original source

Related problems