Existe uma maneira padrão de nomes da lista de módulos Python em um pacote?
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?
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("__")]