Я пытаюсь следовать 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 » и « Импортировать модуль из относительного пути », но они не помогли.
Есть что-то, что я здесь скучаю?
python
package
python-import
importerror
init
skytreader
источник
источник
unittest
проектов, поэтому я написал этот довольно исчерпывающий пример проекта, который охватывает глубокое вложение модулей, относительный и абсолютный импорт (где работают и нет), а также относительные и абсолютные ссылки изнутри пакет, а также одиночный, двойной и импорт классов на уровне пакета. Помогите прояснить вещи прямо для меня!no module named myimports.foo
когда я управляю ими.cd
вPyImports
, и запуститьpython -m unittest tests.test_abs
, например.Ответы:
Да. Вы не используете это как пакет.
источник
__init__.py
весь путь до__package__
конца , и хитрость -modifying (описанную ниже BrenBarn), необходимые для того, чтобы разрешить этот импорт для исполняемых скриптов (например, при использовании shebang и делать./my_script.py
в оболочке Unix) было бы все полезно. Весь этот вопрос был довольно сложным для меня, чтобы выяснить или найти краткую и понятную документацию.pkg
в той точке, где вы вызываете эту строку из CLI. Тогда все должно работать как положено. Если вы внутриpkg
и звонитеpython -m tests.core_test
, это не сработает. По крайней мере, это не для меня.__init__.py
файлы, но вы продолжаете получать сообщение обValueError: Attempted relative import in non-package
ошибке. Я бы где-нибудь заплатил действительно хорошие деньги, чтобы наконец объяснить простым языком, как все это работает.Чтобы развить ответ Игнасио Васкеса-Абрамса :
Механизм импорта Python работает относительно
__name__
текущего файла. Когда вы выполняете файл напрямую, он не имеет своего обычного имени, но"__main__"
вместо этого имеет имя. Так что относительный импорт не работает.Как предложил Игансио, вы можете выполнить его, используя
-m
опцию. Если у вас есть часть вашего пакета, предназначенная для запуска в качестве сценария, вы также можете использовать__package__
атрибут, чтобы сообщить этому файлу, какое имя он должен иметь в иерархии пакетов.Смотрите http://www.python.org/dev/peps/pep-0366/ для подробностей.
источник
python -m core_test
изtests
подкаталога - это должно быть от родителя, или вы должны добавить родителя к пути.__package__
чтобы гарантировать, что исполняемые файлы сценариев могут относительно импортировать другие модули из того же пакета. Нет способа относительно импортировать из "всей системы". Я даже не уверен, почему ты хочешь сделать это.__package__
символа установлено значение «parent.child», вы сможете импортировать «parent.other_child». Возможно, я не так хорошо это сформулировал.script.py
в пакетеpack.subpack
, то установка его__package__
наpack.subpack
позволит вам сделать ,from ..module import something
чтобы импортировать что - то изpack.module
. Обратите внимание, что, как говорится в документации, вы все равно должны иметь пакет верхнего уровня в системном пути. Это уже так работает для импортированных модулей. Единственное, что можно сделать__package__
, это позволить вам использовать это поведение и для непосредственно исполняемых скриптов.__package__
в скрипте , который выполняется непосредственно , но , к сожалению, я получаю следующее сообщение об ошибке: «Родительский модуль„ххх“не загружен, не может выполнить относительный импорт»Вы можете использовать
import components.core
напрямую, если добавляете текущий каталог кsys.path
:источник
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
это также будет работатьfrom os import sys
выглядит как измена :)sys.path
- родительский каталог каталога, в котором находится текущий файл.import sys, os.path as path
.import os; os.sys.path.append(os.path.dirname(os.path.abspath('.')))
. Тогдаimport components.core
у меня работает прямой , импортируя из родительского каталога записной книжки по желанию.Это зависит от того, как вы хотите запустить свой скрипт.
Если вы хотите запустить свой UnitTest из командной строки классическим способом, то есть:
Тогда, так как в этом случае «компоненты» и «тесты» являются братья и сестры папки, вы можете импортировать относительный модуль либо с помощью вставки или на добавление методы sys.path модуля. Что-то вроде:
В противном случае вы можете запустить свой сценарий с аргументом '-m' (обратите внимание, что в данном случае речь идет о пакете, и поэтому вы не должны давать расширение '.py' ), то есть:
В таком случае вы можете просто использовать относительный импорт, как вы это делали:
Наконец, вы можете смешать два подхода, чтобы ваш скрипт работал независимо от того, как он называется. Например:
источник
python -m pdb myscript.py
для запуска сеанса отладки.import pdb; pdb.set_trace()
в код (встроенный).insert
вместоappend
? То есть,sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
В core_test.py сделайте следующее:
источник
Если ваш вариант использования предназначен для выполнения тестов, и он показывает, что это так, то вы можете сделать следующее. Вместо того, чтобы запускать тестовый скрипт,
python core_test.py
используйте среду тестирования, такую какpytest
. Затем в командной строке вы можете ввестиЭто запустит тесты в вашем каталоге. Это обходит вопрос о
__name__
бытии ,__main__
который указывал на @BrenBarn. Затем поместите пустой__init__.py
файл в ваш тестовый каталог, это сделает тестовый каталог частью вашего пакета. Тогда вы сможете сделатьТем не менее, если вы запустите свой тестовый скрипт как основную программу, то снова произойдет сбой. Так что просто используйте тестовый бегун. Может быть, это также работает с другими участниками тестирования, например,
nosetests
но я не проверял это. Надеюсь это поможет.источник
Мое быстрое исправление - добавить каталог в путь:
источник
Проблема связана с вашим методом тестирования,
ты пытался
python core_test.py
тогда вы получите эту ошибку ValueError: Попытка относительного импорта в не пакет
Причина: вы тестируете свою упаковку из непакетного источника.
так что протестируйте свой модуль из исходного кода пакета.
если это структура вашего проекта,
cd pkg
или снаружи pkg /
один,
.
если вы хотите импортировать из папки в том же каталоге. для каждого шага назад добавьте еще один.в
how.py
Incase, если вы хотите импортировать как из hello.py
источник
from .. import how
, как вы импортируете определенный класс / метод из файла 'how'. когда я делаю эквивалент,from ..how import foo
то я получаю «попытку относительного импорта за пределы пакета верхнего уровня»Старая нить. Я обнаружил, что добавление
__all__= ['submodule', ...]
в файл __init__.py и последующее использованиеfrom <CURRENT_MODULE> import *
в целевом объекте работает нормально.источник
Вы можете использовать
from pkg.components.core import GameLoopEvents
, например, я использую pycharm, ниже приведен образ структуры моего проекта, я просто импортирую из корневого пакета, затем он работает:источник
Как сказал Паоло , у нас есть 2 метода вызова:
Одно из различий между ними - строка sys.path [0]. Поскольку интерпретатор будет искать sys.path при выполнении импорта , мы можем сделать с
tests/core_test.py
:И еще после этого мы можем запустить core_test.py с другими методами:
Обратите внимание, py36 проверено только.
источник
Этот подход работал для меня и менее загроможден, чем некоторые решения:
Родительский каталог находится в моем PYTHONPATH, и есть
__init__.py
файлы в родительском каталоге и в этом каталоге.Вышеуказанное всегда работало в Python 2, но Python 3 иногда сталкивался с ImportError или ModuleNotFoundError (последний является новым в Python 3.6 и подклассом ImportError), поэтому следующая настройка работает для меня как в Python 2, так и в 3:
источник
Попробуй это
источник
Если кто-то ищет обходной путь, я наткнулся на один. Вот немного контекста. Я хотел проверить один из методов в файле. Когда я запускаю его изнутри
он всегда жаловался на относительный импорт. Я попытался применить вышеупомянутые решения, но не сработал, так как было много вложенных файлов, каждый с несколькими импортами.
Вот что я сделал. Я только что создал лаунчер, внешнюю программу, которая будет импортировать необходимые методы и вызывать их. Хотя не очень хорошее решение, оно работает.
источник
Вот один из способов, который разозлит всех, но работает довольно хорошо. В тестах запускаем:
Затем просто импортируйте компоненты, как обычно.
источник
Это очень запутанно, и если вы используете IDE, например, pycharm, это немного запутывает. Что сработало для меня: 1. Сделайте настройки проекта Pycharm (если вы запускаете python из VE или из каталога python) 2. Нет ничего плохого в том, как вы определили. иногда это работает с классом импорта из folder1.file1
если это не работает, используйте import folder1.file1. 3. Ваша переменная окружения должна быть правильно указана в системе или указана в аргументе командной строки.
источник
Поскольку ваш код содержит
if __name__ == "__main__"
, который не импортируется как пакет, вам лучше использовать егоsys.path.append()
для решения проблемы.источник
if __name__ == "__main__"
в вашем файле имеет значение для всего, что связано с импортом.