web-dev-qa-db-fra.com

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

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 paquet:

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

Je me demande s'il existe une manière standard ou intégrée 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 un travail considérable pour quelque chose que le mécanisme d’importation de module fait déjà en interne. Cette fonctionnalité est-elle exposée quelque part?

77
DNS

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)])
17
cdleary

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. Vous voudrez peut-être faire quelque chose comme ceci:

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

Je ne sais pas si je néglige quelque chose ou si les réponses sont simplement obsolètes, mais

Comme indiqué par l'utilisateur815423426, cela ne fonctionne que pour les objets dynamiques 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']
7
siebz0r

Ceci est une version récursive qui fonctionne avec Python 3.6 et supérieur:

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
2
tacaswell

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ète utilisant l’aide

>>> import <my package>
>>> help(<my package>)
0
Vlad Bezden

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('isc_datasources')
    for dirpath, _, filenames in os.walk(pathname):
        for  filename in filenames:
            if os.path.splitext(filename)[1] == ".py":
                yield os.path.join(dirpath, filename)
0
Vajk Hermecz

Cela devrait lister les modules:

help("modules")
0
Ammon