Как исправить "Попытка относительного импорта в не-пакет" даже с __init__.py
492 skytreader [2012-07-18 10:59:00]
Я пытаюсь следовать PEP 328 со следующей структурой каталогов:
pkg/
__init__.py
components/
core.py
__init__.py
tests/
core_test.py
__init__.py
В core_test.py
У меня есть следующая инструкция import
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" и "Импортировать модуль из родственника путь", но они не помогли.
Есть ли что-нибудь, что мне не хватает здесь?
python python-import
7 ответов
334 Решение Ignacio Vazquez-Abrams [2012-07-18 11:01:00]
Да. Вы не используете его в качестве пакета.
python -m pkg.tests.core_test
478 BrenBarn [2012-07-18 11:26:00]
Чтобы подробнее ответить на @Ignacio:
Механизм импорта Python работает относительно __name__
текущего файла. Когда вы выполняете файл напрямую, он не имеет своего обычного имени, но вместо него имеет "__main__"
. Таким образом, относительный импорт не работает.
Вы можете, как предложил Игансио, выполнить его с помощью опции -m
. Если у вас есть часть вашего пакета, предназначенного для запуска в качестве script, вы также можете использовать атрибут __package__
, чтобы сообщить этому файлу, какое имя он должен иметь в иерархии пакетов.
Подробнее см. http://www.python.org/dev/peps/pep-0366/.
155 ihm [2013-10-05 00:00:00]
Вы можете использовать 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__))))
118 Paolo Rovelli [2015-01-10 16:36:00]
Это зависит от того, как вы хотите запустить script.
Если вы хотите запустить свой UnitTest из командной строки классическим способом, то есть:
python tests/core_test.py
Тогда, поскольку в этом случае "компоненты" и "тесты" являются палочками сестер, вы можете импортировать относительный модуль либо с помощью метода вставки или добавления sys.path. Что-то вроде:
import sys
from os import path
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
from components.core import GameLoopEvents
В противном случае вы можете запустить script с аргументом '-m' (обратите внимание, что в этом случае речь идет о пакете, и, таким образом, вы не должен давать расширение ".py" ), то есть:
python -m pkg.tests.core_test
В таком случае вы можете просто использовать относительный импорт, как вы делали:
from ..components.core import GameLoopEvents
Вы можете, наконец, объединить два подхода, чтобы ваш script работал независимо от того, как он называется. Например:
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
7 deepak [2015-11-13 20:00:00]
Если ваш вариант использования предназначен для запуска тестов, и он швыряет его, то вы можете сделать следующее. Вместо запуска теста script в качестве python core_test.py
используйте платформу тестирования, такую как pytest
. Затем в командной строке вы можете ввести
$$ py.test
Это запустит тесты в вашем каталоге. Это связано с проблемой __name__
__main__
, на которую указал @BrenBarn. Затем поместите пустой файл __init__.py
в ваш тестовый каталог, это сделает часть каталога теста частью вашего пакета. Тогда вы сможете сделать
from ..components.core import GameLoopEvents
Однако, если вы запустите свой тестовый script в качестве основной программы, тогда все будет терпеть неудачу еще раз. Так что просто используйте тестовый бегун. Возможно, это также работает с другими тестовыми участниками, такими как nosetests
, но я не проверял его. Надеюсь это поможет.
2 Allan Mwesigwa [2017-01-10 20:44:00]
В файле core_test.py выполните следующие действия:
import sys
sys.path.append('../components')
from core import GameLoopEvents
1 v4gil [2016-11-01 10:19:00]
Мое быстрое исправление заключается в добавлении каталога в путь:
import sys
sys.path.insert(0, '../components/')