Как исправить "Попытка относительного импорта в не-пакет" даже с __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/')