У меня есть ситуация, когда в моем проекте Python 3 во время выполнения должны быть включены определенные модули. Я использую importlib.import_module
для этого.
ВТОРОЕ ОБНОВЛЕНИЕ: Я нашел способ сделать что-то близкое к тому, что я хотел. Некоторый дополнительный код, возможно, немного отрисовал мои ссылки здесь. Я опубликую ответ, чтобы показать, что я сделал.
ПЕРВОЕ ОБНОВЛЕНИЕ: Через различные группы Python мне сказали, что это невозможно. У меня есть раздел обновления внизу.
Настройка
Идея состоит в том, что когда пользователь запускает мой сценарий, любые файлы, называемые «агентами _ *. Py» (где * заменяется некоторым словом), ищут классы, и они импортируются. Так, например, файл с именем agents_human.py
будет иметь класс с именем HumanAgent
. Именно этот класс HumanAgent
будет создан, поэтому мне нужно импортировать модуль (файл), чтобы это могло произойти.
Основная проблема
Проблема двоякая:
- Я не могу заставить этот модуль выглядеть в нескольких каталогах.
- Когда моя программа установлена, модуль импорта вообще не работает.
Контекст проблемы
У меня есть кодовая база, которая показывает, что я пытаюсь сделать: https://github.com/jeffnyman/pacumen
Проблема в методе load_agent () ; в частности это утверждение .
Чтобы показать это, если вы клонируете этот репозиторий, вы можете запустить следующую команду из корня проекта:
python3 -m pacumen
- То, что будет работать , если файл
agents_human.py
находится в корне проекта.
- Будет не работать, если файл
agents_human.py
является каталогом agents
в проекте.
В моем репозитории кода файл agents_human.py
находится в каталоге agents
, поэтому импорт не выполняется. Но если этот файл был перемещен в корень, вы увидите, что импорт работает. Тем не менее, как видно из функции load_agent()
, я добавил текущий рабочий каталог плюс каталог «агентов» в путь ( строки 119 - 121 )
Когда я говорю, что импорт не удался, я буквально имею в виду, что: когда вызывается логика для импорта, срабатывает исключение ImportError
. Опять же, это только тогда, когда файл agents_human.py
находится в каталоге agents
.
Проблема, подлежащая решению
В идеале мне бы хотелось, чтобы это работало для обоих подходов: когда файл находится в корне, а когда - в каталоге agents
.
Другой контекст проблемы
Я просто собирался смириться с необходимостью поместить файлы в корень. Но, что еще хуже, при установке программы (в отличие от запуска из корня проекта) даже та часть, которая работает выше, больше не работает.
В частности, из корня проекта клонированного проекта я делаю это:
pip3 install .
Затем я создаю какой-то каталог (скажем, test_pacumen
). Там я поместил файл agents_human.py
, содержимое которого было таким:
class HumanAgent:
pass
(Также требуется каталог layouts
из моего проекта.)
Тогда я бегу:
pacumen
В этом контексте логика никогда не импортирует файл agents_human.py
... даже если он находится в корне того места, откуда выполняется команда.
Что я пробовал
Насколько я понимаю, рассматривая различные примеры, я должен импортировать через относительные имена или предоставлять явную привязку. Но, похоже, это происходит путем предоставления пути, по которому ищут модули. Код, на который я ссылался выше, похоже, делает это.
Я получаю имена модулей, найденные в пути (через эту строку ), и во всех случаях он находит соответствующие файлы, которые я поместил на место. Так что, кажется, путь работает; это не импорт. И здесь я не нахожу много указаний.
Я также попытался просто получить конечную часть пути для каждого пути к файлу следующим образом:
module_end_dir = os.path.basename(os.path.normpath(module_dir))
Затем, с этим на месте, я попробовал это:
agent_module = importlib.import_module(f"{module_end_dir}.{module_name[:-3]}")
Это работает локально, когда agents_human.py
находится в каталоге agents
, но не работает, если agents_human.py
находится в корневом каталоге. И это все еще не работает, когда программа установлена.
Краткое изложение проблем
В контексте первой проблемы (неустановленный контекст) я не знаю, почему модуль agents_human.py
нельзя импортировать из agents
, но его можно импортировать из корня.
Во втором контексте (установленном) кажется, что модуль agents_human.py
не может быть импортирован, даже если он находится в корне.
Я надеюсь, что то, что я привел здесь, не слишком запутанно.
UPDATE:
Мне предложили попробовать что-то подобное для моей load_agent
функции:
def load_agent(pacman, not_human):
module = importlib.import_module("agents.agents_human")
return getattr(module, pacman)
Это работает, когда программа запускается через корневой каталог проекта, но не работает, когда проект устанавливается через pip. Очевидно, это связано с точками входа в сценарии и с тем, как нельзя заставить Python распознавать каталоги как модули в этом контексте.
Был приведен еще один пример, который я понял так:
def load_agent(pacman, not_human):
import re
pysearchre = re.compile('.py$', re.IGNORECASE)
agent_files = filter(pysearchre.search, os.listdir(os.path.join(os.getcwd(), 'agents')))
form_module = lambda fp: '.' + os.path.splitext(fp)[0]
agents = map(form_module, agent_files)
importlib.import_module('agents')
for agent in agents:
if not agent.startswith('__'):
agent_module = importlib.import_module(agent, package="agents")
if pacman in dir(agent_module):
return getattr(agent_module, pacman)
raise Exception("The agent " + pacman + " is not specified in any agents_*.py file.")
Та же ситуация. Это работает с программой при запуске без ее установки; это не когда программа установлена.
Это было в основном служить моим подтверждением того, что то, что я хочу сделать, невозможно, когда программа Python установлена через pip. Я не полностью убежден, но я включаю это обновление на случай, если другие столкнутся с этим.