266

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
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
yarbelk
  • 7,215
  • 6
  • 29
  • 37
  • 7
    I'm curious, what are the downsides to using import? – Chuck Feb 25 '14 at 16:19
  • 32
    If your module has side effects, calling import might have unwanted consequences. So, if you wanted to check which version of a file to run first, you can do check with the below answer, and do the import later. I'm not suggesting it is a good idea to write modules with side effects - but we are all adults and can make our own decisions around how dangerously we want to code. – yarbelk Mar 03 '14 at 03:35
  • 1
    possible duplicate of [How to check if python module exists and can be imported](http://stackoverflow.com/questions/5847934/how-to-check-if-python-module-exists-and-can-be-imported) – ArtOfWarfare Jul 02 '14 at 16:03
  • 2
    @ArtOfWarfare I just closed *that* question you linked as a duplicate of *this* one. Because this question is clearer and also the solution proposed here is better than all other listed there. I'd rather point whoever wants an answer to this better solution than pointing people away from it. – Bakuriu Jul 02 '14 at 21:53
  • @Bakuriu - I proposed this one was a duplicate simply based on age. That one predated this one by a year. It doesn't seem logical that the older one could duplicate a newer one. But I do agree this question looks cleaner and has better answers - for that reason, I wrote up a better answer for the question that is now closed after marking this one a duplicate. – ArtOfWarfare Jul 03 '14 at 09:56
  • @Bakuriu - Are you able to mark my flag as accepted? Since you've already taken action based on it, there's nothing more to be done with it, so it's pointless for it to continue being marked as active. – ArtOfWarfare Aug 04 '14 at 13:15
  • @ArtOfWarfare If I ever come accross that question during review I'll take appropriate action. I've tried to filter the close flags by the tags of this question but it didn't show up, and I don't know of any way to review flags relative to a specific question, so, until then, I can't do much about it. – Bakuriu Aug 09 '14 at 16:49
  • 10
    @Chuck Additionally the module may exist, but may itself contain import errors. Catching ImportErrors as in the code above could lead to indicating the module does not exist, when if fact it does but has errors. – Michael Barton Aug 07 '15 at 18:46
  • There are also packages that take quite a long time to import, for various reasons. – Jules G.M. Jul 15 '21 at 00:08

14 Answers14

300

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
Asherah
  • 18,948
  • 5
  • 53
  • 72
yarbelk
  • 7,215
  • 6
  • 29
  • 37
  • Just a note: there is also `pkgutil.iter_modules()` (via [Alternatives to imp.find_module?](http://stackoverflow.com/questions/5741362/alternatives-to-imp-find-module/14820895#14820895)) – sdaau May 21 '13 at 08:47
  • 4
    This only works for top-level modules, not for `eggs.ham.spam`. – hemflit Jun 13 '13 at 15:44
  • 3
    @hemflit if you want to find `spam` in `eggs.ham` you would use `imp.find_module('spam', ['eggs', 'ham'])` – gitaarik Jan 23 '14 at 12:37
  • 5
    +1, but `imp` is [deprecated](https://docs.python.org/3/library/imp.html) in favor of [`importlib`](https://docs.python.org/3/library/importlib.html) in Python 3. – rvighne Jul 18 '14 at 16:21
  • 4
    What if the imported module contains an actual "ImportError". That's what was happening to me. Then the module exists but will not be "found". – enpenax Jul 25 '14 at 04:38
  • 1
    After a year I came across the same problem I mentioned just above and was digging for a solution for Python 2: `pkgutil.find_loader("my.package.module")` returns a loader if the package/module exists and `None` if not. Please update your answer for Python 2, as masking the ImportError drove me crazy yesterday xP – enpenax Nov 10 '15 at 06:08
  • Actually, find_loader was only introduced, but deprecated(!) in 3.3. So that doesn't work for < 3.3. So `pkgutil.find_loader("my.package.module")` should be the alternative for those versions as well. – Nicklas Börjesson Oct 05 '16 at 11:58
  • The method with `imp` is not working for me using Python 2.7. `import mpl_toolkits' works fine, but the method you provided returns `False` – Jens Munk Apr 04 '17 at 08:58
  • https://docs.python.org/3/library/importlib.html#importlib.util.find_spec – Wtower Apr 15 '17 at 08:36
  • 2
    If you get an error that `importlib` doesn't have a `util` attribute, you can follow [this answer](https://stackoverflow.com/a/39661116/210780) for a fix. – ashes999 Aug 10 '17 at 18:42
  • 1
    @yarbelk Just a little update: the [ModuleNotFoundError](https://docs.python.org/3/library/exceptions.html#ModuleNotFoundError) was introduced in python 3.6. A `try` statement with an `except ModuleNotFoundError` can be used for this purpose (see [my answer](https://stackoverflow.com/a/48006925/7170434)) – J.Baoby Dec 28 '17 at 11:48
  • 1
    When I try the code for Python3 ≥ 3.4, I get the error message `AttributeError: module 'importlib' has no attribute 'util'`. When adding the row `from importlib import util` after `import importlib`, the error disappears. – HelloGoodbye Jul 04 '18 at 09:17
  • 1
    `importlib` appears to be available as early as 2.7. I see no reason to use `imp` if you're not running 2.6 or lower. – jpmc26 Nov 20 '18 at 18:38
  • @jpmc26 Importlib in 2.7 has no find_loader. You can only Import the module (Import_module()). Of cause you can use the Import_module function inside try except. – Saleika Nov 19 '19 at 09:07
44

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
J.Baoby
  • 2,167
  • 2
  • 11
  • 17
  • 24
    This doe not answer the question because it imports the package if it exists – divenex May 04 '20 at 15:50
  • 2
    If another module raises this exception during import, you would not (easily) be able to tell the difference - does your module not exist, or does some of its dependences not exist. – frnhr Feb 07 '21 at 17:30
12

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Zulu
  • 8,765
  • 9
  • 49
  • 56
  • 6
    I downvoted, because this masks import errors in the module, which makes it really hard to spot the error. – enpenax Nov 10 '15 at 02:10
  • 1
    Downvote is a bad idea, a good pratice is "always log catched errors". This is an example after you write how you want it. – Zulu Nov 11 '15 at 02:33
  • 2
    How would you log an error if the imported module fails on line 1 with an ImportError and your try catch makes it fail silently? – enpenax Nov 11 '15 at 04:31
  • I've just run into the masking-import-errors issue in real life, and it was bad (causing tests which should have been failing to pass!). – David Given Jan 10 '19 at 12:12
  • I ran into that where someone was using that error to trigger a monkeypatch on a different module... that was *madness* to find – yarbelk Jul 09 '19 at 05:33
12

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
enpenax
  • 1,476
  • 1
  • 15
  • 27
  • It might have been unclear, but all but the first code blocks do not rely on `ImportError`- please edit if it was unclear to you. – yarbelk Nov 23 '15 at 04:36
  • I see you using the ImportError catch in the first two Python 2 examples. Why are they there, then? – enpenax Nov 23 '15 at 12:53
  • 3
    This throws ImportError if mod == 'not_existing_package.mymodule'. See my full [solution below](http://stackoverflow.com/a/35037157/1763149) – Marcin Raczyński Jan 27 '16 at 12:24
  • 1
    Of course it throws an import error. It is supposed to throw an import error if a module does not exist. That way you can catch it if you need to. The problem with the other solutions is that they mask other errors. – enpenax Jan 28 '16 at 02:48
  • Try/except doesn't mean you mustn't not log or ensure things. You can fully catch any underlying traceback and do anything you want with. – Zulu Jun 07 '18 at 18:29
  • Re *"the current answer"*: Do you mean the *accepted* answer? – Peter Mortensen Apr 04 '22 at 16:14
7

go_as's answer as a one-liner:

 python -c "help('modules');" | grep module
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
5

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())
ArtOfWarfare
  • 20,617
  • 19
  • 137
  • 193
5

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
go_as
  • 77
  • 1
  • 6
  • Nice idea. Like it. Downside: At least on my Win10 the help('modules') command takes what feels like 10 seconds collecting all available modules. If that is no issue, cool command. – Markus-Hermann Jul 16 '21 at 12:03
5

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
Fardin Abdi
  • 1,284
  • 15
  • 20
  • An explanation would be in order. E.g., what is the idea/gist? How does it compare to the previous answers? From [the Help Center](https://stackoverflow.com/help/promotion): *"...always explain why the solution you're presenting is appropriate and how it works"*. Please respond by [editing (changing) your answer](https://stackoverflow.com/posts/58437485/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Apr 04 '22 at 16:25
3

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
User9123
  • 515
  • 2
  • 6
  • 14
1

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
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Marcin Raczyński
  • 944
  • 1
  • 10
  • 14
1

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
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dibrovsd
  • 89
  • 4
  • This fulfills my standard question when programming python: WWDD (What would Django Do?) and I should have look there – yarbelk Jul 09 '19 at 05:28
  • What is the gist of it? E.g., how does it compare to the previous answers (given its increased complexity)? Or should it just be used as a black box without understanding it? Please respond by [editing (changing) your answer](https://stackoverflow.com/posts/36115385/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Apr 04 '22 at 16:18
1

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
jackotonye
  • 3,537
  • 23
  • 31
1

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
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

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)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sylvain
  • 679
  • 9
  • 13