Проблема PATH з pytest 'ImportError: Немає модуля з іменем YadaYadaYada'


231

Я використовував easy_install, щоб встановити pytest на mac, і почав писати тести для проекту з такою структурою файлів, як:

repo/
repo/app.py
repo/settings.py
repo/models.py
repo/tests/
repo/tests/test_app.py

запустившись py.testу каталог репо, все поводиться так, як ви очікували

але коли я спробую те саме, що на Linux або Windows (обидва мають pytest 2.2.3 на них), він гавкає кожного разу, коли потрапляє на перший імпорт чогось із мого шляху програми. Скажімо, наприкладfrom app import some_def_in_app

Чи потрібно мені редагувати свій PATH для запуску py.test у цих системах? Хтось це переживав?


4
Ось спосіб виправити це за допомогою setuptools.
едераг

4
Перевірте відповідь @hoefling і подумайте про зміну прийнятої, якщо так це дозволяє після цього довго: набагато краще!
Девіде

Відповіді:


91

Так, папка-джерело не знаходиться в шляху Python, якщо ви cdпереходите до каталогу тестів.

У вас є два варіанти:

  1. Додайте шлях вручну до тестових файлів, приблизно так:

    import sys, os
    myPath = os.path.dirname(os.path.abspath(__file__))
    sys.path.insert(0, myPath + '/../')
  2. Запустіть тести з env var PYTHONPATH=../.


11
коли я cdпереходжу до каталогу? я біжу py.testвід свого кореня. якщо я не помиляюся, і ви маєте на увазі, як пітест прогулюється через мої папки
MattoTodd

якби це було cdпроблемою, чи не вдарив би я його і на mac?
MattoTodd

О, я неправильно прочитав і подумав, що це не працює з каталогу тестів. все-таки хитрість пропозиції 1 спрацює. Я використовую лише Linux, тому не можу пояснити поведінку на інших ОС.
Not_a_Golfer

чи є такий імпорт у всіх ваших файлах test.py?
MattoTodd

4
так, але структура мого каталогу зазвичай трохи відрізняється - я зазвичай зберігаю / src та / test під кореневою каталогом.
Not_a_Golfer

275

Я не впевнений, чому py.test не додає поточний каталог у сам PYTHONPATH, але ось вирішення (яке потрібно виконати з кореня вашого сховища):

python -m pytest tests/

Це працює тому, що Python додає поточний каталог у PYTHONPATH для вас.


2
Він вимагає перезаписати відносний імпорт до абсолютного, якщо у вас є код для запуску програми не на рівні, з якого ви виконуєте команду. Наприклад: project/test/all-my-testsі project/src/app.pyчерез цю зміну потрібно викликати app.pyпобічно за допомогою __main__.pyфайлу в project/src, щоб можна було використовувати виклик python -m src. Наскільки я можу сказати, безладний матеріал.
Зельфір Кальтшталь

3
@ Zelphir: Рекомендована практика використання абсолютного імпорту. Habnabit's має хорошу статтю про найкращі практики упаковки: blog.habnab.it/blog/2013/07/21/python-packages-and-you , а PEP8 говорить, що "неявний відносний імпорт ніколи не повинен використовуватися і не був видалений у Python 3. " Дивіться: python.org/dev/peps/pep-0008 .
Аптерикс

1
@Apteryx Ви маєте на увазі "абсолютний проект" так? Тому що подібні речі /home/user/dev/projectxyz/src ...були б дуже поганими і не працювали на інших машинах у більшості випадків. Я думаю, що я мав на увазі, що я завжди повинен записувати весь корінь проекту до шляху модуля, навіть якщо модуль знаходиться в тій же папці, що і запуск файлу. Я не знав, що це вважається найкращою практикою, тому це корисна інформація, дякую. Я згоден з більшістю pep8, хоча він все ще не ідеальний.
Зельфір Кальтшталь

1
@ Zelphir, так, саме це я мав на увазі. Я вважаю, що термін абсолютний імпорт в Python завжди позначається як "проект-абсолют". Дивіться: python.org/dev/peps/pep-0328/#rationale-for-absolute-imports . Насправді я впевнений, що ви не можете імпортувати з випадкових, абсолютних локацій, принаймні, використовуючи механізм "імпорт" за замовчуванням.
Аптерикс

4
Я додав __init__.pyу тести, які вирішили проблему. Тепер я можу використовуватиpytest
Кіран Кумар Котарі

154

conftest рішення

Найменш інвазивним рішенням є додавання порожнього файлу, названого conftest.pyв repo/каталозі:

$ touch repo/conftest.py

Це воно. Не потрібно писати спеціальний код для керування sys.pathабо не забудьте перетягнути PYTHONPATHабо розміщувати __init__.pyв грі там, де йому не належить.

Після цього каталог проектів:

repo
├── conftest.py
├── app.py
├── settings.py
├── models.py
└── tests
     └── test_app.py

Пояснення

pytestзовнішній вигляд для conftestмодулів на тестовій колекції , щоб зібрати призначені для користувача гачки і кріплення, а також для того , щоб імпортувати призначені для користувача об'єкти з них, pytestдодає батьківський каталог conftest.pyдоsys.path (в цьому випадку repoкаталогу).

Інші структури проекту

Якщо у вас є інша структура проекту, розмістіть conftest.pyу кореневому пакеті dir (той, що містить пакунки, але не є самим пакетом, тому не містить __init__.py), наприклад:

repo
├── conftest.py
├── spam
   ├── __init__.py
   ├── bacon.py
   └── egg.py
├── eggs
   ├── __init__.py
   └── sausage.py
└── tests
     ├── test_bacon.py
     └── test_egg.py

src макет

Хоча цей підхід можна використовувати з srcмакетом (місце conftest.pyв режимі src):

repo
├── src
   ├── conftest.py
   ├── spam
      ├── __init__.py
      ├── bacon.py
      └── egg.py
   └── eggs 
       ├── __init__.py
       └── sausage.py
└── tests
     ├── test_bacon.py
     └── test_egg.py

потрібно враховувати , що додавання srcдо PYTHONPATHпом'якшують сенс і переваги srcкирилиці! Ви закінчите тестування коду із сховища, а не встановленого пакету. Якщо вам потрібно це зробити, можливо, вам зовсім не потрібен srcреж.

Куди піти звідси

Звичайно, conftestмодулі - це не лише деякі файли, які допомагають виявити вихідний код; саме там pytestвідбуваються всі покращення рамки та налаштування вашого тестового набору. pytestмає багато інформації про conftestмодулі, розкидані по їхніх документах ; Почніть з conftest.py: локальних плагінів для директорій

Крім того, SO має відмінне запитання щодо conftestмодулів: У py.test, для чого використовують файли conftest.py?


2
@ aaa90210, хоча я не можу відтворити вашу проблему (імпорт з контесту в кореневий редактор працює на будь-якому рівні), ви ніколи не повинні імпортувати файли з конфіденцій, оскільки це зарезервоване ім'я, pytestі настійно радимо цього не робити. Тим самим ви садите насіння для майбутніх помилок. Створіть інший модуль з назвою utils.pyта вставте код для повторного використання в тестах.
гофлінг

4
Пальці вгору! Це єдине рішення, яке добре працює для мене.
130nrd

4
повинна бути абсолютно прийнятою відповіддю - дякую!
Мартін Пек

2
За логікою, conftest.pyне належить до коду програми, і, imo, розміщення його src/не є правильним.
Нік О'Лай

2
Ця відповідь має бути фіксованим заголовком на SO. Дуже дякую.
Рігоберта Равіоліні

119

У мене була така ж проблема. Я виправив це, додавши порожній __init__.pyфайл у свій testsкаталог.


77
Зауважте, що це НЕ рекомендується py.test: avoid “__init__.py” files in your test directories. This way your tests can run easily against an installed version of mypkg, independently from the installed package if it contains the tests or not.SRC: pytest.org/latest/goodpractises.html
K.-Michael Aye

24
Я прийшов сюди з тим же питанням і виявив, що видалення __init__.pyз мого каталогу тестів вирішило це для мене.
101

3
@mafro Я не бачу проблеми? Тести не повинні бути імпортованими кодами, їх знайде ваш тест-бігун. Тільки код, який слід перевірити, повинен бути встановленим пакетом / модулем, а не тестами.
K.-Michael Aye

5
Додавання __init__.pyв підкаталогах test/робить абсолютною імпортну роботу для запуску конкретних тестів у цьому підкаталозі щодо модулів, що встановлюються. Дякую.
Брайс Гінта

7
там ви переходите: doc.pytest.org/en/latest/goodpractices.html дуже просто знайти в Google.
К.-Майкл Айе

46

Запустити pytestсебе як модуль із: python -m pytest tests


3
Це здається робочим рішенням, але хто може пояснити ЧОМУ? Я вважаю за краще виправити основну причину, ніж просто використовувати python -m pytestбез будь-яких пояснень, окрім "тому, що це працює"
Janne Enberg

4
Це відбувається, коли наприклад є ієрархія проекту: package/src package/testsі в testsімпорті з src. Виконання в якості модуля вважатиме імпорт абсолютним, ніж відносно місця виконання.
Стефано Мессіна

1
Це рішення допомогло мені, дякую! Причиною цього було через конфлікт у версії Python. тест pytest працює для більш ранньої версії python. У моїй ситуації моя версія python становить 3.7.1, python -m пітест-тести працюють, але не pytest тести.
Руксі Чжан

1
З Pytest "Запуск pytest з python -m pytest [...] замість pytest [...] дає майже еквівалентну поведінку, за винятком того, що колишній виклик додасть поточний каталог у sys.path."
Moad Ennagi

37

Ви можете працювати з PYTHONPATH в корені проекту

PYTHONPATH=. py.test

Або використовувати встановлення pip як імпорт, який можна редагувати

pip install -e .   # install package using setup.py in editable mode

3
Це не працювало для мене з testкаталогом, який не знаходиться в srcструктурі каталогу, і виклику з каталогу, що містить testі srcкаталог, і каталог.
Зельфір Кальтшталь

21

Я створив це як відповідь на ваше запитання і мою власну плутанину. Я сподіваюся, що це допомагає. Зверніть увагу на PYTHONPATH як в командному рядку py.test, так і в tox.ini.

https://github.com/jeffmacdonald/pytest_test

Конкретно: Ви повинні повідомити py.test і токсинувати, де знайти модулі, до яких ви входите.

З py.test ви можете це зробити:

PYTHONPATH=. py.test

І разом з токсином додайте це до свого tox.ini:

[testenv]
deps= -r{toxinidir}/requirements.txt
commands=py.test
setenv =
    PYTHONPATH = {toxinidir}

1
Не могли б ви дати коротке пояснення для пов'язаного вами проекту?
JF Meier

1
Можливо, це тільки я, але README щодо проекту досить детальний, і мій коментар щодо stackoverflow говорить про те, чому я створив репо.
Джефф Макдональд

5
Хоча це суворо і не обов'язково, звичайна політика має основний зміст відповіді у самій відповіді, оскільки це гарантує, що відповідь зрозуміла через x років з цього моменту, коли пов'язаний ресурс може давно піти.
JF Meier

:) Що ж, добре. Ось Інтернет для тебе.
Джефф Макдональд

9

У мене була така ж проблема в колбі.

Коли я додав:

__init__.py

до папки тестів, проблема зникла :)

Можливо, програма не змогла розпізнати тести папок як модуль


8

Я виправив це, видаливши верхній рівень __init__.pyу батьківській папці своїх джерел.


1
Виправлено це для мене. Хтось може це пояснити?
абобер

це саме тут виправило це і для мене. Безумовно, хотілося б побачити пояснення цьому, якщо хтось має
king_wayne

Я додав init .py, але все ще стикався з тими ж проблемами, але це рішення працювало і для мене.
Абхіджіт

7

Я почав отримувати дивні ConftestImportFailure: ImportError('No module named ...помилки, коли випадково додав __init__.pyфайл до свого каталогу src (який не повинен був бути пакетом Python, а лише контейнером усіх джерел).


3

Я отримував цю помилку через щось навіть простіше (можна сказати навіть тривіально). Я не встановив pytestмодуль. Так простоapt install python-pytest зафіксований для мене.

"pytest" був би зазначений у setup.py як тестова залежність. Переконайтесь, що ви також встановили вимоги до тесту.


3

У мене було подібне питання. pytestне розпізнав модуль, встановлений у середовищі, в якому я працював.

Я вирішив це, встановивши pytestв те саме середовище.


Хоча я використовував pytest зсередини вену, я також встановив його глобально, що дало мені цю помилку. Після видалення глобальної версії та встановлення всередині він працював.
Маркус Рессел

2

Для мене проблема була tests.pyстворена Django разом з testsкаталогом. Видалення tests.pyвирішило проблему.


2

Я отримав цю помилку, оскільки я неправильно використовував відносний імпорт. У прикладі OP, test_app.py повинен імпортувати функції, використовуючи напр

from repo.app import *

Однак, як правило, файли __init__.py розкидані по всій структурі файлів, це не працює і створює тип ImportError, який спостерігається, якщо файли та тестові файли не в одному каталозі.

from app import *

Ось приклад того, що я мав робити з одним із своїх проектів:

Ось моя структура проекту:

microbit/
microbit/activity_indicator/activity_indicator.py
microbit/tests/test_activity_indicator.py

Щоб мати доступ до Activity_indicator.py з test_activity_indicator.py, мені потрібно було:

  • запустіть test_activity_indicatory.py з правильним відносним імпортом:
    from microbit.activity_indicator.activity_indicator import *
  • розмістити файли __init__.py у всій структурі проекту:
    microbit/
    microbit/__init__.py
    microbit/activity_indicator/__init__.py
    microbit/activity_indicator/activity_indicator.py
    microbit/tests/__init__.py
    microbit/tests/test_activity_indicator.py

0

Дуже часто тести переривали через неможливість імпорту модуля. Після дослідження я з’ясував, що система шукає файл у неправильному місці, і ми можемо легко подолати проблему, скопіювавши файл, що містить модуль, у ту саму папку, що і вказана, для належного імпорту. Ще однією пропозицією рішення буде змінити декларацію про імпорт і показати MutPy правильний шлях одиниці. Однак через те, що декілька одиниць можуть мати цю залежність, тобто ми повинні вносити зміни і в їх декларації, ми віддаємо перевагу просто перемістити одиницю в папку.


Є й інші відповіді, які забезпечують питання ОП, і вони були опубліковані деякий час тому. Опублікувавши відповідь, будь ласка, переконайтесь, що ви додали або нове рішення, або істотно краще пояснення, особливо, відповідаючи на старі питання. Іноді краще опублікувати коментар до певної відповіді.
help-info.de

На додаток до коментаря від @ help-info.de: Ось посилання на посібник для відповідей на запитання: stackoverflow.com/help/how-to-answer
рука NOD

0

Згідно з публікацією на Medium від Dirk Avery (і підтримується моїм особистим досвідом), якщо ви використовуєте віртуальне середовище для свого проекту, тоді ви не можете використовувати загальносистемну установку pytest; ви повинні встановити його у віртуальному середовищі та використовувати його.

Зокрема, якщо ви встановили її в обох місцях, просто виконання pytestкоманди не буде працювати, оскільки вона буде використовувати систему установки. Як описано в інших відповідях, одне просте рішення - запустити python -m pytestзамість pytest; це працює, оскільки він використовує середовище версію pytest. Крім того, ви можете просто видалити версію системи pytest системи; після реактивації віртуального середовища pytestкоманда повинна працювати.


Єдине, що до цього працювало для мене, було python -m pytest tests/.
Нік О'Лай

0

У мене виникли ті ж проблеми, коли слідкуючи за підручником з колбою, і я знайшов відповідь в офіційних документах Pytest. Це невеликий зсув від того, як я (і, думаю, багато інших) звикли робити щось.

Ви повинні створити setup.pyфайл у кореневому каталозі вашого проекту, принаймні з наступних двох рядків:

from setuptools import setup, find_packages
setup(name="PACKAGENAME", packages=find_packages())

де PACKAGENAME - назва вашого додатка. Тоді вам доведеться встановити його за допомогою pip:

pip install -e .

-eПрапор говорить ПГИ intall пакета в редагованому або «розвивати» режим. Тож наступного разу, коли ви запустите, ви pytestповинні знайти свою програму у стандартному форматі PYTHONPATH.


0

Моє рішення:

створити conftest.pyфайл у testкаталозі, що містить:

import os
import sys
sys.path.insert(0,os.path.dirname(os.path.realpath(__file__)) + "/relative/path/to/code/")

Це додасть папку, що цікавить, до шляху python, не змінюючи кожен тестовий файл , встановивши змінну env або змішавшись з абсолютними / відносними шляхами.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.