Импорт Python, когда скрипты запускаются из другой папки (предка)

У меня есть большой репозиторий с некоторой фиксированной структурой, и я расширил его некоторыми папками и скриптами Python, чтобы добавить к нему дополнительную функциональность в целом. Структура выглядит следующим образом:

  • toplevelfolder
    • featureA
      • someModuleA.py
      • __ инициализировать __.py
    • featureB
      • someModuleB.py
      • __ инициализировать __.py
    • заявление
    • __ инициализировать __.py
    • app.py

Теперь someModuleA.py и someModuleB.py можно вызывать через app.py, но в то же время их можно вызывать напрямую, однако этот вызов должен исходить из папки верхнего уровня, чтобы относительные пути в файле разрешались правильно, то есть через python ./featureA/someModuleA.py.

Все это работает хорошо, но теперь мне нужны некоторые определения функций из someModuleB в someModuleA, и поэтому я хочу импортировать этот модуль. Я пробовал как абсолютный, так и относительный импорт, но оба терпят неудачу с разными ошибками, абсолютный импорт с

from toplevelfolder.featureA import someModuleA as A

# ModuleNotFoundError: No module named 'toplevelfolder'

и относительный импорт с

from toplevelfolder.featureA import someModuleA as A

# ImportError: attempted relative import with no known parent package

Теперь я вижу, что относительный импорт вызовет проблемы, когда python вызывается из toplevelfolder, поскольку .. будет представлять родительский каталог последнего, а не родительский каталог featureA. Однако я не могу получить первое сообщение об ошибке, тем более что toplevelfolder должен быть не модулем, а пакетом.

Есть ли другой способ импорта в Python, о котором я не знаю, возможно, без изменения PYTHONPATH или sys.path или чего-то в этом роде?


person Jens Eirik Sæthre    schedule 08.05.2020    source источник
comment
Я бы рекомендовал называть ваш код исполняемым модулем, например: path/to/pythonX.Y -m toplevelfolder.app вместо path/to/pythonX.Y toplevelfolder/app.py.   -  person sinoroc    schedule 08.05.2020
comment
@sinoroc, который не решает проблему, и меня больше интересует запуск someModuleA, а не app в папке верхнего уровня.   -  person Jens Eirik Sæthre    schedule 08.05.2020
comment
Называется ли он app, или foo, или bar, не имеет значения. Конечно, вам всегда придется адаптировать приведенные здесь ответы к вашему конкретному варианту использования. В любом случае... Если вы всегда используете абсолютный импорт, это должно работать. Предполагается, что пакеты и модули верхнего уровня действительно находятся либо в текущем рабочем каталоге, либо установлены в пакетах сайта.   -  person sinoroc    schedule 08.05.2020
comment
Вставьте это выше вашего импорта:` ``` import os,sys,inspect currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) parentdir = os.path.dirname( текущий каталог) sys.path.insert(0,parentdir) ```   -  person Theodor Peifer    schedule 08.05.2020
comment
вместо того, чтобы возиться с sys.path, вы должны попытаться превратить свой проект в устанавливаемый пакет: packaging.python .org/tutorials/packaging-projects   -  person Arne    schedule 08.05.2020
comment
@sinoroc нет, очевидно, имя не имеет значения, но в описанном мной сценарии app находится в папке верхнего уровня, тогда как someModuleA находится в подпапке, но все же файл python в папке (т.е. someModuleA.py) запускается из папки верхнего уровня, что делает сценарий отличается от того, что описывает ваш ответ. Более того, я думаю, что ясно заявил, что абсолютный импорт не работает в этом конкретном сценарии, когда someModuleA.py запускается из папки верхнего уровня, а не из папки featureA. Но все равно спасибо :)   -  person Jens Eirik Sæthre    schedule 09.05.2020


Ответы (3)


Не уверен на 100%, какая цель здесь. Мой совет будет:

  1. Четко определите, какими должны быть ваши модули и пакеты верхнего уровня.

  2. Сделать весь импорт абсолютным.

  3. Либо:

    • make your project a real installable project, so that those top level modules and packages are installed in the environment's site-packages directory;
    • или убедитесь, что текущий рабочий каталог содержит модули и пакеты верхнего уровня.
  4. Обязательно вызывайте свой код с помощью метода исполняемого модуля или пакета вместо метода скрипта, если точка входа, которую вы хотите выполнить, является частью пакета

    • DO (executable module or package):
      • path/to/pythonX.Y -m toplevelpackage.module
      • path/to/pythonX.Y -m toplevelpackage.subpackage (при условии, что есть файл toplevelpackage/subpackage/__main__.py)
    • DON'T (script within a package):
      • path/to/pythonX.Y toplevelpackage/module.py
  5. (Необязательно) Позже, когда все будет хорошо работать и все будет под контролем, вы можете изменить некоторые или все импорты на относительные. (Если все сделано правильно, я считаю, что можно было бы сделать так, чтобы исполняемые модули можно было вызывать с любого уровня в структуре каталогов в качестве текущего рабочего каталога.)

Ссылки:

person sinoroc    schedule 09.05.2020

Не включайте каталог верхнего уровня. В featureB.someModuleB:

from featureA.someModuleA import two

Образец каталога.

person gerardw    schedule 06.04.2021

Попробуйте вставить это над вашим импортом:

import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir) 

Затем вы сможете импортировать файл из родительской папки.

person Theodor Peifer    schedule 08.05.2020