Не работает импорт модуля по абсолютному пути в python
Структура проекта такая:
my_project
|
|___database
| |
|___api
| |
| |___db_api.py
|
|___models
| |
| |__film
| |_user
|_recomendation
Я запуская скрипт db_api в котором модули из папки models импортируются так
from database.models.film import Film
from database.models.user import User
from database.models.recomendation import Recomendation
И я получаю ошибку
Exception has occurred: ModuleNotFoundError
No module named 'database'
File "/home/vor/vscode_WS/db_sqlalchemy_practice/database/api/database_api.py", line 6, in <module>
from database.models.film import Film
ModuleNotFoundError: No module named 'database'
Я знаю, что относительные пути нельзя использовать в скриптах, которые непосредственно запускаются, но я использую абсолютный! В чем проблема, подскажите?
Ответы (3 шт):
возможно, не так понял вопрос, но, может, мой ответ чем то поможет:
По Вашей структуре получается, что в database
у вас действительно нет директории models
, она находится в my_project
. Возможно, вот так нужно сделать импорт:
from my_project.models.film import Film
Я бы сделал классический пакет с файлом __unit__.py
, и туда бы напихал все импорты.
примерно:
Абсолютный импорт точно так же как и относительный работает только внутри пакета, т.е. чтобы работало, нужно запускать командой python -m database.api.db_api
из корня проекта.
Когда вы запускаете модуль как скрипт, импорт вида from database.models.film import Film
для интерпретатора Python означает, что в папке со скриптом (либо по какому-то из путей из переменной окружения PYTHONPATH
) должен находиться пакет (папка) database
, в нем пакет models
, в нем модуль film
, и из модуля уже нужно импортировать класс Film
. Интерпретатор в этом случае не смотрит на уровни выше, а смотрит только в папке скрипта и папках из PYTHONPATH
.
Если запускать db_api
как модуль из пакета, то интерпретатор поймет, что мы находимся в пакете database
. И что в этом же пакете нужно искать, то что мы импортируем, в данном случае по абсолютному импорту от "корня" пакета, а не от директории, запускаемый модуль находится.
Можно, конечно, добавить корень проекта в PYTHONPATH
, но это костыльное решение. Нормальное решение — запускать как пакет.
Для упрощения запуска можно в корень проекта (рядом с папкой database
) добавить "пусковой" скрипт, в нем импортировать db_api
. Предположим, что в db_api
у вас есть функция main
, ее запуск идет в блоке if __name__ == "__main__":
(код не стартует просто при импорте). Тогда в пусковом файле пишем что-то типа:
from database.api.db_api import main
if __name__ == "__main__":
main()
Если в db_api
пусковой код не в if __name__ == "__main__":
, то он сработает просто при импорте, дополнительно вызывать ничего не нужно будет. Но я бы не советовал так оставлять, лучше спрятать код в этот блок, а в корневом пусковом файле явно запускать то что вам нужно ("явное лучше неявного").
Есть несколько способов решения такой проблемы:
$PYTHONPATH
В Python вы можете создать (или обновить) переменную окружения PYTHOPATH, работает она так же как и стандартная системная переменная $PATH, только если $PATH указывает где искать пути к исполняемым файлам, PYTHONPATH указывает пути к пакетам питона. Особенно удобно это может быть при испоьзовании virtualenv
, ведь вы можете добавить экспорт этой переменной в скрипт активации виртуальной среды, примерно так:
export PYTHONPATH=/home/artur1214/ptest/my_project && python3 db_api.py
(структура проекта:)
Кстати, почти наверняка в Pycharm ваш код бы работал, потому что он автоматически добавляет к PYTHONPATH путь до текущего проекта.
Но такой способ очень неудобен:
Придется придется постоянно разбираться как правильно настроить PYTHONPATH при переносе на новый компьютер или просто переносе проекта в другую папку.
Запуск из файла.
Создайте в корне проекта условный main.py
from database.api.db_api import *
#...код
При этом вы импорты будут работать. Основной код вы можете продолжать писать внутри db_api, или (лучше) перенести тесты в main.py, а в db_api оставить только логику модуля api
Если совсем невмоготу, вы можете написать в самом верху db_api вот такой код:
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
Он добавляет в системный список путей путь до корня проекта относительно db_api.py. (По сути то же самое, что PYTHONPATH, только из питона) Но на мой взгляд это полукостыльное решение.