web-dev-qa-db-de.com

Gibt es eine Standardmethode, um Namen von Python-Modulen in einem Paket aufzulisten?

Gibt es eine einfache Möglichkeit, die Namen aller Module in einem Paket aufzulisten, ohne __all__ zu verwenden?

Zum Beispiel dieses Paket gegeben:

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

Ich frage mich, ob es eine Standardmethode oder eine integrierte Methode gibt, um so etwas zu tun:

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

Der manuelle Ansatz besteht darin, die Modulsuchpfade zu durchlaufen, um das Verzeichnis des Pakets zu finden. Man könnte dann alle Dateien in diesem Verzeichnis auflisten, die eindeutig benannten py/pyc/pyo-Dateien herausfiltern, die Erweiterungen entfernen und diese Liste zurückgeben. Dies scheint jedoch ziemlich viel Arbeit für etwas zu sein, was der Modulimportmechanismus bereits intern erledigt. Ist diese Funktionalität irgendwo ausgesetzt?

77
DNS

Vielleicht wird das tun, was Sie suchen?

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

Mit python2.3 und höher können Sie auch das Modul pkgutil verwenden:

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

EDIT: Beachten Sie, dass es sich bei dem Parameter nicht um eine Liste von Modulen handelt, sondern um eine Liste von Pfaden. Daher möchten Sie vielleicht Folgendes tun:

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

Ich weiß nicht, ob ich etwas übersehe oder ob die Antworten nur veraltet sind;

Wie von user815423426 angegeben, funktioniert dies nur für Live-Objekte und die aufgeführten Module sind nur Module, die zuvor importiert wurden.

Das Auflisten von Modulen in einem Paket scheint mit inspect sehr einfach zu sein:

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

Dies ist eine rekursive Version, die mit Python 3.6 und höher funktioniert:

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

Wenn Sie Informationen zu Ihrem Paket außerhalb des Python-Codes anzeigen möchten (über eine Eingabeaufforderung), können Sie pydoc verwenden.

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

Sie erhalten dasselbe Ergebnis wie pydoc, jedoch innerhalb des Interpreters mithilfe der Hilfe

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

Basierend auf dem Beispiel von cdleary ist hier ein rekursiver Versionspfad für alle Submodule:

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

Dies sollte die Module auflisten:

help("modules")
0
Ammon