Как рекурсивно получить все подмодули в пакете python?
Задача
У меня есть такая структура папок:
- modules
- root
- abc
hello.py
__init__.py
- xyz
hi.py
__init__.py
blah.py
__init__.py
foo.py
bar.py
__init_.py
Вот то же самое в строковом формате:
"modules",
"modues/__init__.py",
"modules/foo.py",
"modules/bar.py",
"modules/root",
"modules/root/__init__.py",
"modules/root/blah,py",
"modules/root/abc",
"modules/root/abc/__init__.py",
"modules/root/abc/hello.py",
"modules/root/xyz",
"modules/root/xyz/__init__.py",
"modules/root/xyz/hi.py"
Я пытаюсь распечатать все модули в формате стиля импорта python. Пример вывода будет выглядеть так:
modules.foo
modules.bar
modules.root.blah
modules.root.abc.hello
modules.root.xyz.hi
Как я могу сделать это в python(если это возможно без сторонних библиотек) легко?
Что я пробовал
Пример Кода
import pkgutil
import modules
absolute_modules = []
def find_modules(module_path):
for package in pkgutil.walk_packages(module_path):
print(package)
if package.ispkg:
find_modules([package.name])
else:
absolute_modules.append(package.name)
if __name__ == "__main__":
find_modules(modules.__path__)
for module in absolute_modules:
print(module)
Однако этот код будет выводить только "foo" и "bar". Но не "корень", а это субпакеты. Мне также трудно понять, как преобразовать это, чтобы сохранить его абсолютный стиль импорта. Текущий код получает только имя пакета / модуля, а не фактический абсолютный импорт.2 ответа:
Приведенный ниже код даст вам относительный модуль пакета из текущего рабочего каталога кодов.
import os import re for root,dirname,filename in os.walk(os.getcwd()): pth_build="" if os.path.isfile(root+"/__init__.py"): for i in filename: if i <> "__init__.py" and i <> "__init__.pyc": if i.split('.')[1] == "py": slot = list(set(root.split('\\')) -set(os.getcwd().split('\\'))) pth_build = slot[0] del slot[0] for j in slot: pth_build = pth_build+"."+j print pth_build +"."+ i.split('.')[0]
Этот код будет отображать:
modules.foo modules.bar modules.root.blah modules.root.abc.hello modules.root.xyz.hi
Если вы запустите его вне папки modules.
Так что я, наконец, понял, как сделать это чисто и заставить pkgutil позаботиться обо всем случае edge для вас. Этот код был основан на python
help()
функция, которая отображает только модули и пакеты верхнего уровня.import importlib import pkgutil import sys import modules def find_abs_modules(module): path_list = [] spec_list = [] for importer, modname, ispkg in pkgutil.walk_packages(module.__path__): import_path = f"{module.__name__}.{modname}" if ispkg: spec = pkgutil._get_spec(importer, modname) importlib._bootstrap._load(spec) spec_list.append(spec) else: path_list.append(import_path) for spec in spec_list: del sys.modules[spec.name] return path_list if __name__ == "__main__": print(sys.modules) print(find_abs_modules(modules)) print(sys.modules)
Это будет работать даже для встроенных пакетов.