Existe-t-il une méthode standard pour répertorier les noms des modules Python dans un package?

StackOverflow https://stackoverflow.com/questions/487971

  •  20-08-2019
  •  | 
  •  

Question

Existe-t-il un moyen simple de répertorier les noms de tous les modules d'un package sans utiliser __all__?

Par exemple, étant donné ce package:

/testpkg
/testpkg/__init__.py
/testpkg/modulea.py
/testpkg/moduleb.py

Je me demande s'il existe un moyen standard ou intégré de faire quelque chose comme ceci:

>>> package_contents("testpkg")
['modulea', 'moduleb']

L’approche manuelle consisterait à parcourir les chemins de recherche du module afin de trouver le répertoire du paquet. Vous pouvez ensuite répertorier tous les fichiers de ce répertoire, filtrer les fichiers py / pyc / pyo, nommés de manière unique, effacer les extensions et renvoyer cette liste. Mais cela semble être une lourde tâche pour quelque chose que le mécanisme d’importation de module fait déjà en interne. Cette fonctionnalité est-elle exposée quelque part?

Était-ce utile?

La solution

Peut-être que cela fera ce que vous cherchez?

import imp
import os
MODULE_EXTENSIONS = ('.py', '.pyc', '.pyo')

def package_contents(package_name):
    file, pathname, description = imp.find_module(package_name)
    if file:
        raise ImportError('Not a package: %r', package_name)
    # Use a set because some may be both source and compiled.
    return set([os.path.splitext(module)[0]
        for module in os.listdir(pathname)
        if module.endswith(MODULE_EXTENSIONS)])

Autres conseils

En utilisant python2.3 et supérieur , vous pouvez également utiliser le module pkgutil :

>>> import pkgutil
>>> [name for _, name, _ in pkgutil.iter_modules(['testpkg'])]
['modulea', 'moduleb']

EDIT: Notez que le paramètre n'est pas une liste de modules, mais une liste de chemins. Par conséquent, vous souhaiterez peut-être procéder de la manière suivante:

>>> import os.path, pkgutil
>>> import testpkg
>>> pkgpath = os.path.dirname(testpkg.__file__)
>>> print [name for _, name, _ in pkgutil.iter_modules([pkgpath])]
import module
help(module)

Je ne sais pas si j'oublie quelque chose ou si les réponses sont désuètes mais;

Comme indiqué par l'utilisateur815423426, cela ne fonctionne que pour les objets vivants et les modules répertoriés ne sont que des modules importés auparavant.

La liste des modules dans un paquet semble très facile avec inspect :

>>> import inspect, testpkg
>>> inspect.getmembers(testpkg, inspect.ismodule)
['modulea', 'moduleb']

Ceci est une version récursive qui fonctionne avec Python 3.6 et versions ultérieures:

import importlib.util
from pathlib import Path
import os
MODULE_EXTENSIONS = '.py'

def package_contents(package_name):
    spec = importlib.util.find_spec(package_name)
    if spec is None:
        return set()

    pathname = Path(spec.origin).parent
    ret = set()
    with os.scandir(pathname) as entries:
        for entry in entries:
            if entry.name.startswith('__'):
                continue
            current = '.'.join((package_name, entry.name.partition('.')[0]))
            if entry.is_file():
                if entry.name.endswith(MODULE_EXTENSIONS):
                    ret.add(current)
            elif entry.is_dir():
                ret.add(current)
                ret |= package_contents(current)


    return ret

Ceci devrait lister les modules:

help("modules")

Si vous souhaitez afficher une information sur votre paquet en dehors du code python (à partir d'une invite de commande), vous pouvez utiliser pydoc pour cela.

# get a full list of packages that you have installed on you machine
$ python -m pydoc modules

# get information about a specific package
$ python -m pydoc <your package>

Vous obtiendrez le même résultat que pydoc mais à l'intérieur de l'interpréteur à l'aide de l'aide

>>> import <my package>
>>> help(<my package>)

D'après l'exemple de cdleary, voici un chemin de liste de version récursif pour tous les sous-modules:

import imp, os

def iter_submodules(package):
    file, pathname, description = imp.find_module(package)
    for dirpath, _, filenames in os.walk(pathname):
        for  filename in filenames:
            if os.path.splitext(filename)[1] == ".py":
                yield os.path.join(dirpath, filename)

print dir (module)

def package_contents(package_name):
  package = __import__(package_name)
  return [module_name for module_name in dir(package) if not module_name.startswith("__")]
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top