Pergunta

Existe uma maneira simples de listar os nomes de todos os módulos em um pacote, sem usar __all__?

Por exemplo, dado este pacote:

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

Eu estou querendo saber se existe um padrão ou built-in maneira de fazer algo parecido com isto:

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

A abordagem manual seria a de percorrer os caminhos de pesquisa de módulo, a fim de encontrar o diretório do pacote. Pode-se, em seguida, listar todos os arquivos no diretório, filtrar o py / pyc / pyo arquivos de nome exclusivo, tira as extensões, e retornar essa lista. Mas esta parece ser uma boa quantidade de trabalho para algo que o mecanismo de importação módulo já está fazendo internamente. É que a funcionalidade exposta em qualquer lugar?

Foi útil?

Solução

Talvez isso vai fazer o que você está procurando?

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

Outras dicas

Usando python2.3 e acima , você também pode usar o módulo pkgutil:

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

EDIT: Note que o parâmetro não é uma lista de módulos, mas uma lista de caminhos, para que você pode querer fazer algo como isto:

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

não sei se eu estou com vista algo, ou se as respostas são apenas out-datada, mas;

Como afirmado por user815423426 isso só funciona para objetos vivos e os módulos listados são apenas os módulos que foram importados antes.

Listagem módulos em um pacote parece realmente fácil usando inspecionar :

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

Esta é uma versão recursiva que funciona com o python 3.6 e acima:

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

Isso deve listar os módulos:

help("modules")

Se você gostaria de ver um inforamtion sobre o seu lado de fora do pacote do código python (a partir de um prompt de comando), pode utilizar pydoc para ele.

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

Você terá o mesmo resultado que pydoc mas dentro de intérprete usando a ajuda

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

Com base no exemplo de cdleary, aqui está uma versão recursiva lista caminho para todos os sub-módulos:

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)

dir impressão (módulo)

def package_contents(package_name):
  package = __import__(package_name)
  return [module_name for module_name in dir(package) if not module_name.startswith("__")]
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top