Макет и импорт для pytest в python3 - PullRequest
0 голосов
/ 15 октября 2018

У меня проблемы с импортом модулей из моих функций pytest.Я знаю, что есть миллион вопросов по этому вопросу, но я прочитал кучу, и у меня все еще есть проблемы с пониманием.

$ tree
.
└── code
    ├── eight_puzzle.py
    ├── missionaries_and_cannibals.py
    ├── node.py
    ├── search.py
    └── test
        ├── test_eight_puzzle.py
        └── test_search.py

2 directories, 6 files
$
$ grep import code/test/test_search.py
import sys
import pytest
import code.search
$
$ pytest
...
ImportError while importing test module '~/Documents/code/test/test_search.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
code/test/test_search.py:14: in <module>
    import code.search
E   ModuleNotFoundError: No module named 'code.search'; 'code' is not a package
...

Я ожидал, что это сработает.«Код» - это пакет, верно?Пакет в Python 3 - это любой каталог с файлами .py в нем.

Я также попробовал его с относительным импортом - from .. import search - и получаю следующее.

ImportError while importing test module '~/Documents/code/test/test_search.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
code/test/test_search.py:14: in <module>
    from .. import search
E   ImportError: attempted relative import with no known parent package

Я также попытался изменить sys.path, как показано здесь , указав мой PYTHONPATH и добавив init .py файлы в коде и тесте.

Можно ли заставить этот импорт работать без использования чего-то вроде setuptools?Это просто для экспериментов, поэтому я бы предпочел не иметь дело с накладными расходами.

Также может быть важно отметить, что я использую conda, потому что, кажется, работает, когда я использую python 2установленная pip версия pytest с файлами init .py.

1 Ответ

0 голосов
/ 15 октября 2018

Некоторые примечания о каталогах без __init__.py файлов:

Неявные пакеты пространства имен

Хотя каталог без __init__.py является допустимым источником импорта в Python 3, он не являетсяобычный пакет, скорее неявный пакет пространства имен (подробности см. PEP 420 ).Среди других свойств неявные пакеты пространства имен являются гражданами второго сорта, когда речь заходит об импорте. Это означает, что когда в Python есть два пакета с одинаковыми именами в sys.path, один из которых является обычным пакетом, а другой - неявным пакетом пространства имен, обычныйбудет предпочтительным независимо от того, какой пакет идет первым.Проверьте сами:

$ mkdir -p implicit_namespace/mypkg
$ echo -e "def spam():\n    print('spam from implicit namespace package')" > implicit_namespace/mypkg/mymod.py
$ mkdir -p regular/mypkg
$ touch regular/mypkg/__init__.py
$ echo -e "def spam():\n    print('spam from regular package')" > regular/mypkg/mymod.py
$ PYTHONPATH=implicit_namespace:regular python3 -c "from mypkg.mymod import spam; spam()"

Будет напечатано spam from regular package: хотя implicit_namespace стоит первым в sys.path, вместо него mypkg.mymod из regular импортируется, потому что regular/mypkg является обычным пакетом.


Теперь вы знаете, что, поскольку ваш пакет code является неявным пакетом пространства имен, Python предпочтет регулярный импорт code вашему, если он его встретит.К сожалению для вас, в stdlib есть модуль code, так что это практически проблема "обратного дублирования имен": у вас есть объект импорта с тем же именем, что и у stdlib, но вместоотслеживая импорт stdlib, он затеняет ваше.

Таким образом, вам нужно сделать две вещи, чтобы сделать ваш макет пригодным для использования:

  1. дать code dir уникальное имя (пустьэто будет mycode для примера этого ответа)
  2. после этого вам все еще нужно исправить sys.path при запуске тестов из корневого каталога проекта, потому что он не находится в sys.path как таковом.У вас есть несколько возможностей:
    • добавить пустой файл conftest.py в корневой каталог (кроме mycode dir).Это заставит pytest добавить корневой каталог к ​​sys.path (объяснение см. здесь ).Теперь вы можете просто запустить pytest как обычно, и импорт будет разрешен;
    • запустить тесты через python -m pytest - вызов интерпретатора напрямую добавляет текущий каталог в sys.path;
    • addтекущий каталог sys.path через PYTHONPATH env var, например, запустить PYTHONPATH=. pytest.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...