Если файл Python внутри пакета вызывает ошибку ImportError: attempted relative import with no known parent package при прямом запуске, запустите его как модуль из каталога, находящегося над пакетом. В macOS перейдите в корень проекта в Terminal, затем выполните python3 -m package.module. Это предоставит Python контекст пакета, который не обеспечивает прямой путь к файлу.
Почему относительный импорт завершается ошибкой при прямом запуске файла?
Относительный импорт, такой как from .helpers import format_result, зависит от имени пакета модуля. Python использует начальные точки для определения текущего пакета и его родительских элементов. Когда вы запускаете файл с помощью python3 path/to/file.py, Python выполняет этот файл как модуль верхнего уровня __main__; он не предоставляет ему метаданные пакета, необходимые для разрешения точки. Поэтому импорт может завершиться ошибкой, даже если файл helpers.py находится рядом с запускаемым файлом. В справочнике по импорту Python описаны относительные импорты и специальная обработка __main__.
Например, предположим, что структура вашего проекта выглядит следующим образом:
project/
└── myapp/
├── __init__.py
├── cli.py
└── helpers.py
Если cli.py содержит строку from .helpers import format_result, то выполнение команды python3 myapp/cli.py из каталога project является неверным вызовом. Проблема заключается в том, как именно Python попросили запустить файл, а не обязательно в ошибке относительного импорта или расположения файлов.
Запуск модуля из корня проекта в macOS
Откройте Terminal и перейдите в каталог, содержащий myapp. Замените путь из примера на реальное расположение вашего проекта. Заключите путь в кавычки, чтобы оболочка корректно обработала пробелы; оболочкой по умолчанию в macOS Terminal является zsh. Руководство Apple по Terminal документирует это значение по умолчанию.
cd "/Users/yourname/Projects/project"
python3 -m myapp.cli
Параметр -m указывает Python найти и запустить модуль по его имени в пакете с разделителями-точками. Сохраняйте имя пакета в команде и опускайте .py и файловые слэши. Путь поиска модулей Python при вызове с флагом -m начинается с текущего каталога, поэтому запуск из корня проекта имеет принципиальное значение. Документация Python по sys.path объясняет этот начальный путь.
Если команда использует не ту установку Python, сначала активируйте существующее виртуальное окружение проекта, а затем используйте тот же шаблон python -m. Для стандартного окружения .venv в корне проекта:
cd "/Users/yourname/Projects/project"
source .venv/bin/activate
python -m myapp.cli
Использование команды python после активации выбирает интерпретатор окружения. Если ваше окружение имеет другое имя или расположение, скорректируйте путь активации; не предполагайте, что .venv существует по умолчанию. Вы можете проверить выбранный интерпретатор с помощью команды python -c 'import sys; print(sys.executable)'.
Если вы хотите запустить сам пакет
Для команды, предназначенной для запуска самого пакета, добавьте __main__.py внутрь пакета и сделайте точку входа лаконичной:
myapp/
├── __init__.py
├── __main__.py
├── cli.py
└── helpers.py
В файле myapp/__main__.py импортируйте и вызовите входную функцию пакета. Затем выполните python3 -m myapp из корня проекта. Для такой формы вызова -m Python выполняет файл __main__.py пакета, и этот файл может использовать относительные импорты пакета. Документация Python по __main__ объясняет этот паттерн точки входа в пакет.
Проверьте эти детали, если ошибка сохраняется
- Проверьте текущую рабочую директорию. Выполните команду
pwdв Terminal и убедитесь, что она выводит корень проекта — каталог, содержащийmyapp. Если пакет вложен, например, в папкуsrc, используйте импортируемое имя пакета и убедитесь, что настроенное окружение проекта делает его доступным; простой переход в неправильную родительскую папку не исправит обнаружение модулей. - Используйте настоящее имя пакета. В команде
python3 -m myapp.cliимяmyappдолжно быть именем каталога пакета (или его именем при импорте), аcli— именем файла модуля без.py. - Проверьте строку в трейсбеке. Если относительный импорт разрешается, но последующий импорт завершается ошибкой, дело может быть в отсутствии другого модуля или зависимости. Исправление контекста запуска устраняет только ошибку контекста пакета.
- Не используйте
PYTHONPATHв качестве первого решения. Эта переменная изменяет путь поиска импортов в Python, но сама по себе не превращает напрямую выполняемый файл в корректно именованный модуль пакета. Python также предупреждает, чтоPYTHONPATHможет влиять на несколько версий и окружений Python. Справочник по инициализации путей в Python описывает область ее действия. - Если прямой запуск файла является обязательным требованием, рассмотрите возможность изменения кода для использования подходящего абсолютного импорта и убедитесь, что пакет установлен или доступен для импорта в этом окружении иным способом. Это принципиально другой подход к настройке; не следует совмещать относительный импорт пакета с ожиданием, что файл будет работать как автономный скрипт.
Практическое правило заключается в том, чтобы сопоставлять команду со стилем импорта: для относительного импорта пакета запускайте модуль из родительского каталога пакета с помощью python -m. Для команды запуска пакета предоставьте __main__.py и запускайте пакет с ключом -m.
Источники
- 5. The import system — Python Software Foundation
- The initialization of the sys.path module search path — Python Software Foundation
- main — Top-level code environment — Python Software Foundation
- Change the default shell in Terminal on Mac — Apple