PEP8 - импортировать не поверх файла с sys.path

проблема

PEP8 имеет правило о вводе импорта в начало файла:

Импорт всегда помещается в верхнюю часть файла, сразу после комментариев модуля и доклингов, а также перед глобалами и константами модуля.

Однако в некоторых случаях я могу сделать что-то вроде:

import sys
sys.path.insert("..", 0)

import my_module

В этом случае pep8 командной строки pep8 мой код:

Импорт уровня модуля E402 не поверх файла

Каков наилучший способ добиться соответствия sys.path изменениям sys.path?

Зачем

У меня есть этот код, потому что я следую структуре проекта, приведенной в руководстве Hitchhiker для Python.

Это руководство предполагает, что у меня есть папка my_module, отдельно от папки tests, оба из которых находятся в одном каталоге. Если я хочу получить доступ к my_module из tests, я думаю, что мне нужно добавить .. на sys.path

Ответы

Ответ 1

Часто у меня есть несколько файлов с тестами в подкаталоге foo/tests моего проекта, а модули, которые я тестирую, находятся в foo/src. Чтобы запустить тесты из foo/tests без ошибок импорта, я создаю файл foo/tests/pathmagic.py который выглядит следующим образом:

"""Path hack to make tests work."""

import os
import sys

bp = os.path.dirname(os.path.realpath('.')).split(os.sep)
modpath = os.sep.join(bp + ['src'])
sys.path.insert(0, modpath)

В каждом тестовом файле я затем использую

import pathmagic  # noqa

как первый импорт. Комментарий "noqa" не позволяет pycodestyle/pep8 жаловаться на неиспользуемый импорт.

Ответ 2

Если есть только несколько импортов, вы можете просто игнорировать PEP8 в этих строках import:

import sys
sys.path.insert("..", 0)
import my_module  # noqa: E402

Ответ 3

Существует еще одно обходное решение.

import sys
... all your other imports...

sys.path.insert("..", 0)
try:
    import my_module
except:
    raise

Ответ 4

Я просто боролся с подобным вопросом, и я думаю, что нашел немного более приятное решение, чем принятый ответ.

Создайте модуль pathmagic который выполняет фактическую манипуляцию sys.path, но внесите изменения в менеджер контекста:

"""Path hack to make tests work."""

import os
import sys

class context:
    def __enter__(self):
        bp = os.path.dirname(os.path.realpath('.')).split(os.sep)
        modpath = os.sep.join(bp + ['src'])
        sys.path.insert(0, modpath)

    def __exit__(self, *args):
        pass

Затем в ваших тестовых файлах (или там, где вам это нужно) вы делаете:

import pathmagic

with pathmagic.context():
    import my_module
    # ...

Таким образом, вы не получаете никаких жалоб от flake8/pycodestyle, вам не нужны специальные комментарии, и, похоже, структура имеет смысл.

Для дополнительной аккуратности рассмотрите возможность возврата пути в блоке __exit__, хотя это может вызвать проблемы с ленивым импортом (если вы поместите код модуля вне контекста), возможно, это не стоит того.


EDIT: Просто увидел гораздо более простой трюк в ответе на другой вопрос: добавьте assert pathmagic под свой импорт, чтобы избежать комментария noqa.

Ответ 5

Чтобы соответствовать pep8, вы должны указать свой путь к пути python для выполнения относительного/абсолютного импорта.

Для этого вы можете взглянуть на этот ответ: постоянно добавлять каталог в PYTHONPATH

Ответ 6

Вы уже попробовали следующее:

import sys
from importlib import import_module

sys.path.insert("..", 0)

# import module
my_mod = import_module('my_module')

# get method or function from my_mod
my_method = getattr(my_mod , 'my_method')