Вопрос-Ответ

How to fix "Attempted relative import in non-package" even with __init__.py

Как исправить "Попытку относительного импорта без пакета" даже с __init__.py

Я пытаюсь следовать PEP 328 со следующей структурой каталогов:

pkg/
__init__.py
components/
core.py
__init__.py
tests/
core_test.py
__init__.py

В core_test.py у меня есть следующий оператор импорта

from ..components.core import GameLoopEvents

Однако при запуске я получаю следующую ошибку:

tests$ python core_test.py 
Traceback (most recent call last):
File "core_test.py", line 3, in <module>
from ..components.core import GameLoopEvents
ValueError: Attempted relative import in non-package

Поискав вокруг, я нашел "относительный путь не работает даже с __init__.py" и "Импортировать модуль по относительному пути", но они не помогли.

Есть ли что-то, чего мне здесь не хватает?

Переведено автоматически
Ответ 1

Подробнее об ответах Игнасио Васкеса-Абрамса:

Механизм импорта Python работает относительно __name__ текущего файла. Когда вы запускаете файл напрямую, он не имеет своего обычного имени, но вместо этого имеет "__main__" в качестве имени. Таким образом, относительный импорт не работает.

Вы можете, как предложил Игансио, выполнить это с помощью -m опции. Если у вас есть часть вашего пакета, которая предназначена для запуска как скрипт, вы также можете использовать __package__ атрибут, чтобы сообщить этому файлу, какое имя он должен иметь в иерархии пакетов.

Подробнее см. http://www.python.org/dev/peps/pep-0366 / .

Ответ 2

ДА. Вы не используете его как пакет.

python -m pkg.tests.core_test
Ответ 3

Это зависит от того, как вы хотите запустить свой скрипт.

Если вы хотите запустить UnitTest из командной строки классическим способом, то есть:

python tests/core_test.py

Затем, поскольку в этом случае 'components' и 'tests' являются родственными папками, вы можете импортировать относительный модуль либо с помощью метода insert, либо append модуля sys.path.
Что-то вроде:

import sys
from os import path
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
from components.core import GameLoopEvents

В противном случае вы можете запустить свой скрипт с аргументом '-m' (обратите внимание, что в данном случае мы говорим о пакете, и, следовательно, вы не должны указывать расширение '.py'), то есть:

python -m pkg.tests.core_test

В таком случае вы можете просто использовать относительный импорт, как вы делали:

from ..components.core import GameLoopEvents

Вы, наконец, можете смешать два подхода, чтобы ваш скрипт работал независимо от того, как он вызван.
Например:

if __name__ == '__main__':
if __package__ is None:
import sys
from os import path
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
from components.core import GameLoopEvents
else:
from ..components.core import GameLoopEvents
Ответ 4

Вы можете использовать import components.core напрямую, если добавите текущий каталог в sys.path:

if __name__ == '__main__' and __package__ is None:
from os import sys, path
sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
python