web-dev-qa-db-fra.com

Comment vérifier si un module python existe sans l'importer

J'ai besoin de savoir si un module python existe, sans l'importer.

Importer quelque chose qui pourrait ne pas exister (pas ce que je veux):

try:
    import eggs
except ImportError:
    pass
148
yarbelk

Python2

Pour vérifier si l'import peut trouver quelque chose dans python2, utilisez imp

import imp
try:
    imp.find_module('eggs')
    found = True
except ImportError:
    found = False

Pour rechercher des importations pointillées, vous devez en faire plus:

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

Vous pouvez également utiliser pkgutil.find_loader (plus ou moins la même chose que la partie python3

import pkgutil
eggs_loader = pkgutil.find_loader('eggs')
found = eggs_loader is not None

Python3

Python3 ≤ 3,3

Vous devriez utiliser importlib, voici comment je me suis débrouillé pour le faire:

import importlib
spam_loader = importlib.find_loader('spam')
found = spam_loader is not None

Mon attente est, si vous pouvez trouver un chargeur pour cela, alors il existe. Vous pouvez également être un peu plus intelligent à ce sujet, comme filtrer les chargeurs que vous accepterez. Par exemple:

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)

Python3 ≥ 3.4

En Python3.4, importlib.find_loaderpython docs était obsolète en faveur de importlib.util.find_spec. La méthode recommandée est le importlib.util.find_spec. Il en existe d'autres comme importlib.machinery.FileFinder, utile si vous souhaitez charger un fichier spécifique. Comprendre comment les utiliser va au-delà de la portée de ceci.

import importlib
spam_spec = importlib.util.find_spec("spam")
found = spam_spec is not None

Cela fonctionne également avec les importations relatives, mais vous devez fournir le package de départ. Vous pouvez également effectuer les opérations suivantes:

import importlib
spam_spec = importlib.util.find_spec("..spam", package="eggs.bar")
found = spam_spec is not None
spam_spec.name == "eggs.spam"

Bien que je sois sûr qu'il existe une raison pour cela, je ne suis pas sûr de ce que ce serait.

ATTENTION

Lorsque vous essayez de trouver un sous-module, il importera le module parent (pour toutes les méthodes ci-dessus)!

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.find_spec("food.eggs")
module food loaded
ModuleSpec(name='food.eggs', loader=<_frozen_importlib.SourceFileLoader object at 0x10221df28>, Origin='/home/user/food/eggs.py')

les commentaires sont les bienvenus pour résoudre ce problème

Remerciements

  • @rvighne pour importlib
  • @ lucas-guido pour python3.3 + dépréciation find_loader
  • @enpenax pour le comportement de pkgutils.find_loader dans python2.7
172
yarbelk

Après avoir utilisé la réponse de yarbelk, j'ai créé ceci pour ne pas avoir à importer ìmp.

try:
    __import__('imp').find_module('eggs')
    # Make things with supposed existing module
except ImportError:
    pass

Utile dans settings.py de Django par exemple.

13
Zulu

Python 2, sans compter ImportError

Jusqu'à ce que la réponse actuelle soit mise à jour, voici le chemin pour Python 2

import pkgutil
import importlib

if pkgutil.find_loader(mod) is not None:
    return importlib.import_module(mod)
return None

Pourquoi une autre réponse?

Beaucoup de réponses utilisent la capture d'une ImportError. Le problème avec cela est que nous ne pouvons pas savoir ce qui jette le ImportError.

Si vous importez votre module existant et qu'il se trouve qu'il y ait un ImportError dans votre module (par exemple une faute de frappe sur la ligne 1), le résultat sera que votre module n'existe pas. Il vous faudra toute une série de retours en arrière pour déterminer que votre module existe et que la variable ImportError est interceptée et provoque l'échec des choses en silence.

11
enpenax

la réponse de go_as en une ligne

 python -c "help('modules');" | grep module
8
user2268226

Je suis tombé sur cette question alors que je cherchais un moyen de vérifier si un module est chargé à partir de la ligne de commande et voudrais partager mes pensées pour celles à venir. après moi et cherchant le même:

Méthode de fichier de script Linux/UNIX : créer un fichier module_help.py:

#!/usr/bin/env python

help('modules')

Ensuite, assurez-vous qu'il est exécutable: chmod u+x module_help.py

Et appelez-le avec un pipe à grep:

./module_help.py | grep module_name

Appelez le système intégré système d'aide . (Cette fonction est destinée à une utilisation interactive .) Si aucun argument n'est fourni, le système d'aide interactif démarre sur la console d'interprétation. Si l'argument est une chaîne , la chaîne est recherchée comme nom d'un module , fonction, classe, méthode, mot clé ou sujet de documentation, et une page d'aide est imprimée sur la console. Si l'argument est un autre type d'objet, une page d'aide sur cet objet est générée.

Méthode interactive : chargement dans la console python

>>> help('module_name')

Si trouvé, quittez la lecture en tapant q
Pour quitter la session interactive python, appuyez sur Ctrl + D

Méthode du fichier de script Windows également compatible Linux/UNIX, et meilleur dans l'ensemble :

#!/usr/bin/env python

import sys

help(sys.argv[1])

L'appeler à partir de la commande comme:

python module_help.py site  

Serait sortie:

Aide sur le site du module:

NAME site - Ajoute les chemins de recherche de modules pour les packages tiers à sys.path.

FILE /usr/lib/python2.7/site.py

MODULE DOCShttp://docs.python.org/library/site

DESCRIPTION
...
:

et vous devez appuyer sur q pour quitter le mode interactif.

Utilisation de ce module inconnu:

python module_help.py lkajshdflkahsodf

Serait sortie:

no Python documentation trouvée pour 'lkajshdflkahsodf'

et sortir.

6
go_as

Utilisez l’un des fonctions de pkgutil , par exemple:

from pkgutil import iter_modules

def module_exists(module_name):
    return module_name in (name for loader, name, ispkg in iter_modules())
5
ArtOfWarfare

Python 3> = 3.6: ModuleNotFoundError

Le ModuleNotFoundError a été introduit dans python 3.6 et peut être utilisé à cette fin.

try:
    import eggs
except ModuleNotFoundError:
    # Error handling
    pass

L'erreur est déclenchée lorsqu'un module ou l'un de ses parents est introuvable. Alors

try:
    import eggs.sub
except ModuleNotFoundError as err:
    # Error handling
    print(err)

afficherait un message ressemblant à No module named 'eggs' si le module eggs est introuvable; mais afficherait quelque chose comme No module named 'eggs.sub' si seul le module sub était introuvable, mais que le package eggs soit également trouvé.

Voir le documentation du système d'importation pour plus d'informations sur le ModuleNotFoundError

4
J.Baoby

Vous pouvez simplement écrire un petit script qui tente d'importer tous les modules et vous indique ceux qui échouent et ceux qui fonctionnent:

import pip


if __== '__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))

Sortie:

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

Mot d'avertissement cela va essayer d'importer tout donc vous verrez des choses comme PyYAML failed with error code: No module named pyyaml parce que le nom d'importation réel est juste yaml. Donc, tant que vous connaissez vos importations, cela devrait faire l'affaire pour vous.

4
User9123

Une déclaration if plus simple de AskUbuntu: Comment vérifier si un module est installé en Python?

import sys
print('eggs' in sys.modules)
3
Sylvain

Vous pouvez également utiliser importlib directement

import importlib

try:
    importlib.import_module(module_name)
except ImportError:
    # Handle error
2
jackotonye

dans 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
1
dibrovsd

Il n’existe aucun moyen de vérifier de manière fiable si un "module en pointillé" est importable sans importer son paquet parent. Cela dit, il existe de nombreuses solutions au problème "comment vérifier si le module Python existe".

La solution ci-dessous résout le problème selon lequel un module importé peut générer ImportError, même s'il existe. Nous voulons distinguer cette situation de celle dans laquelle le module n’existe pas.

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:

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
1
Marcin Raczyński