pytest не может импортировать модуль, а python может


116

Я работаю над пакетом на Python. Я использую virtualenv. Я установил путь к корню модуля в пути .pth в моем virtualenv, чтобы я мог импортировать модули пакета при разработке кода и проводить тестирование (вопрос 1: это хороший способ?). Это отлично работает (вот пример, это то, что я хочу):

(VEnvTestRc) zz@zz:~/Desktop/GitFolders/rc$ python
Python 2.7.12 (default, Jul  1 2016, 15:12:24) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from rc import ns
>>> exit()
(VEnvTestRc) zz@zz:~/Desktop/GitFolders/rc$ python tests/test_ns.py 
issued command: echo hello
command output: hello

Однако, если я попытаюсь использовать PyTest, я получаю сообщения об ошибках импорта:

(VEnvTestRc) zz@zz:~/Desktop/GitFolders/rc$ pytest
=========================================== test session starts ============================================
platform linux2 -- Python 2.7.12, pytest-3.0.5, py-1.4.31, pluggy-0.4.0
rootdir: /home/zz/Desktop/GitFolders/rc, inifile: 
collected 0 items / 1 errors 

================================================== ERRORS ==================================================
________________________________ ERROR collecting tests/test_ns.py ________________________________
ImportError while importing test module '/home/zz/Desktop/GitFolders/rc/tests/test_ns.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
tests/test_ns.py:2: in <module>
    from rc import ns
E   ImportError: cannot import name ns
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
========================================= 1 error in 0.09 seconds ==========================================
(VEnvTestRc) zz@zz:~/Desktop/GitFolders/rc$ which pytest
/home/zz/Desktop/VirtualEnvs/VEnvTestRc/bin/pytest

Я немного озадачен, похоже, это указывает на ошибку импорта, но Python справляется с этим нормально, так почему конкретно проблема с PyTest? Есть какие-нибудь предложения по поводу причины / решения (Вопрос 2)? Я погуглил и переполнил стек с ошибкой «ImportError: невозможно импортировать» для PyTest, но полученные мной совпадения были связаны с отсутствием пути Python и исправлением этого, что, похоже, не является проблемой здесь. Какие-либо предложения?

Ответы:


119

Нашел ответ:

НЕ помещайте __init__.pyфайл в папку, содержащую ТЕСТЫ, если вы планируете использовать pytest. У меня был один такой файл, удаление его решило проблему.

Фактически это было похоронено в комментариях ко второму ответу на проблему PATH с pytest 'ImportError: No module named YadaYadaYada', поэтому я его не видел, надеюсь, здесь он станет более заметным.


46
Веселая. У меня была такая же проблема, и мне пришлось добавить init .py в папку с тестами.
Ev.

5
Да, это не общее решение (хотя оно и было в вашем случае), чтобы понять, почему это следует читать: docs.pytest.org/en/latest/goodpractices.html#test-package-name
juan

1
Эта информация НЕПРАВИЛЬНА и вводит в заблуждение! После добавления init .py в тестовую папку все работало нормально
Леонардо Остан

1
@LeonardoOstan может быть неправильным для вас, но это не значит, что эта информация в целом неверна. В моем случае это решило проблему.
Desprit,

83

Я не могу сказать, что понимаю, почему это работает, но у меня была та же проблема, и тесты работают нормально, если я бегу python -m pytest.

Я нахожусь в virtualenv, а pytest также доступен во всем мире:

(proj)tom@neon ~/dev/proj$ type -a python
python is /home/tom/.virtualenvs/proj/bin/python
python is /usr/bin/python

(proj)tom@neon ~/dev/proj$ python -V
Python 3.5.2

(proj)tom@neon ~/dev/proj$ type -a pytest
pytest is /home/tom/.virtualenvs/proj/bin/pytest
pytest is /usr/bin/pytest

(proj)tom@neon ~/dev/proj$ pytest --version
This is pytest version 3.5.0, imported from /home/tom/.virtualenvs/proj/lib/python3.5/site-packages/pytest.py

1
Также выполнил эту работу для меня, дело в том, что он запускается версией python, определенной вместо вашего v.env.
Nebulosar

13
одна из причин может заключаться в том, что python -m pytest [...]"также добавит текущий каталог в sys.path".
minusf 05

Если бы то же самое в Windows 10, и работает питон -m pytest решил это
Duccio

Это сработало и в моей виртуальной среде, которую я должен был запуститьpython3 -m pytest
Риши Радж

На основе комментария @minusf я использую PYTHONPATH=.:./src pytestкак цель make.
Ян Грот,

29

Я просто решил это, удалив __init__.py в корне моего проекта:

.
├── __init__.py <--- removed
├── models
   ├── __init__.py
   ├── address.py
   ├── appointment.py
   └── client.py
├── requirements.txt
├── setup.cfg
├── tests
   ├── __init__.py
   ├── models
      ├── __init__.py
      ├── appointment_test.py
      └── client_test.py
   └── other_test.py
└── script.py

4
Принятый ответ __init__.py file in a folder containing TESTSне решил мою проблему. Этот сработал. Думаю, это из-за иерархии файлов.
smido

Я удалил __init__.pyфайл. Я все еще сталкивался с проблемой. Добавление файла conftest.py в корневой каталог сработало для меня.
Виджай Сали

Я ожидал, что conftest.py будет в / tests, а не в корне,
Аарон Макмиллин,

Получение файла conftest.py в корневой каталог также исправило это для меня. В каталоге тестов нет файла init .py
обновление

2
Это решение сработало для меня, но знает ли кто-нибудь, что это вызовет ошибку импорта?
Альдо Окваре,

20

У меня была такая же проблема, но по другой причине, чем упомянутые:

У меня был установлен py.test глобально, а пакеты были установлены в виртуальной среде.

Решение было установить pytestв виртуальной среде. (В случае, если ваша оболочка хеширует исполняемые файлы, как это делает Bash, используйте hash -rили используйте полный путь к py.test)


2
Только что понял, что у меня такая же подлая проблема с использованием анаконды. Я забыл добавить pytestvirtualenv, созданный conda, но pytestон доступен в корневой среде anaconda. Поэтому pytest может быть найден, но не любой пакет , установленный в среде.
Overdrivr

1
Я была такая же проблема. pytest был установлен глобально, а не в virtualenv. pip3 install pytestвнутри virtualenv исправлена ​​проблема.
Анкит Сингх

7

Эта проблема может возникнуть, если у вас есть tests.pyфайл и папка тестов сtests/__init__.py .

Во время сбора pytest находит папку, но когда он пытается импортировать тестовые файлы из папки, tests.pyфайл вызывает проблему импорта.

Чтобы исправить, просто удалите tests.pyфайл и поместите все свои тесты в tests/папку.

Для вашего конкретного случая исправление будет именно таким:

  • Удалить файл /home/zz/Desktop/GitFolders/rc/tests.py
  • Убедитесь, что /home/zz/Desktop/GitFolders/rc/tests/__init__.pyприсутствует

4

У меня была аналогичная проблема, точно такая же ошибка, но по другой причине. Я отлично запускал тестовый код, но со старой версией модуля. В предыдущей версии моего кода один класс существовал, а другой - нет. После обновления кода я должен был запустить следующее, чтобы установить его.

sudo pip install ./ --upgrade

После установки обновленного модуля запуск pytest дал правильные результаты (потому что я использовал правильную кодовую базу).


1
Это сработало для меня! Мой модуль был одновременно установлен как библиотека в контейнере докера, который я использовал для запуска pytest. При запуске интерпретатора python он найдет обновленный код, но pytest продолжит поиск кода, как это было при первой установке библиотеки. Запуск pip install ./ --upgradeобновил установленную версию библиотеки последним кодом и позволил pytest найти и эту последнюю версию.
FaustoW

4

Установите пакеты в вашу виртуальную среду.
Затем запустите новую оболочку и снова создайте свою виртуальную среду.


1
Это была моя проблема: новая установка без перезагрузки venv
замороженный

4

В моем случае ошибка импорта произошла из-за того, что пакет указывает на другой пакет / каталог с тем же именем, а его путь находится на один уровень выше папки, которую я действительно хотел. Я думаю, это также объясняет, почему некоторым людям нужно удалить _ init _.py, а другим нужно добавить обратно.

Я просто поставил print(the_root_package.__path__)(после import the_root_package) как в pythonконсоли, так и в pytestскриптах, чтобы сравнить разницу

ИТОГ: В pythonэтом случае пакет, который вы импортируете, может отличаться от пакета при запуске pytest.


2

Ответ выше не работает для меня. Я просто решил это, добавив абсолютный путь модуля, который не найден, sys.pathвверху test_xxx.py(вашего тестового модуля), например:

import sys
sys.path.append('path')

1
Вместо того, чтобы помещать эти строки вверху моей страницы test_main.py, я поместил ее conftest.pyв свой тестовый каталог, и он сработал. Спасибо за программное решение вместо файлового мусора.
Кэмерон Хадсон

2

Если это связано с кодом Python, который изначально был разработан в Python 2.7, а теперь перенесен в Python 3.x, то проблема, вероятно, связана с проблемой импорта.

например, при импорте объекта из файла: baseкоторый находится в том же каталоге, это будет работать в python 2.x:

from base import MyClass

в python 3.x вы должны заменить baseполный путь, иначе .base это вызовет указанную выше проблему. поэтому постарайтесь:

from .base import MyClass

2

Сегодня я столкнулся с этой проблемой и решил ее, позвонив python -m pytest из корневого каталога моего проекта.

Звонки pytestиз того же места по-прежнему вызывали проблемы.

Мой каталог проекта организован как:

api/
 - server/
  - tests/
      - test_routes.py
  - routes/
      - routes.py
 - app.py

Модуль routesбыл импортирован у меня test_routes.pyкак:from server.routes.routes import Routes

Надеюсь, это поможет!


Спасибо за напоминание, мне приходилось использовать этот трюк в прошлом, и он есть в документации pytest.
Джейсон Стивенс CFA,

2

Была аналогичная проблема, и она сработала, когда я добавил __init__.pyфайл в каталог тестов.


не знаю, почему это работает, но это так !!! большое спасибо :)
Gooseman

1

Другой частный случай:

У меня возникла проблема с использованием tox. Итак, моя программа работала нормально, но юнит-тесты через tox продолжали жаловаться. После установки пакетов (необходимых для программы) вам необходимо дополнительно указать пакеты, используемые в unittests, в файле tox.ini

[testenv]
deps =
    package1
    package2 
...

1

Я получал это с помощью VSCode. У меня среда conda. Я не думаю, что расширение Python VScode могло видеть обновления, которые я делал.

python c:\Users\brig\.vscode\extensions\ms-python.python-2019.9.34911\pythonFiles\testing_tools\run_adapter.py discover pytest -- -s --cache-clear test
Test Discovery failed:

Мне пришлось бежать pip install ./ --upgrade


Эта команда pip возвращает ошибку:Directory './' is not installable. Neither 'setup.py' nor 'pyproject.toml' found.
Дерек

1

Отредактируйте свой conftest.py и добавьте следующие строки кода:

import os, sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(file), '..')))

И если вы пытаетесь запустить тестовый пример через терминал, используйте следующий пример:

python -m pytest test_some_step_file_steps.py --html=HTML_step_file_output.html --self-contained-html

NameError: name 'file' is not defined- чему должен равняться файл?
Кошмар,

1

Еще одна крупная победа для системы импорта Python. Я думаю, причина отсутствия консенсуса в том, что то, что работает, вероятно, зависит от вашей среды и инструментов, которые вы используете поверх нее.

Я использую это из VS Code в обозревателе тестов под Windows в среде conda, Python 3.8.

Настройка, с которой мне нужно работать:

mypkg/
    __init__.py
    app.py
    view.py
tests/
    test_app.py
    test_view.py

При этой настройке работает intellisense и обнаружение тестов.

Обратите внимание, что я изначально пробовал следующее, как рекомендовано здесь .

src/
    mypkg/
        __init__.py
        app.py
        view.py
tests/
    test_app.py
    test_view.py

Я не мог найти способ заставить это работать из VS Code, потому что srcпапка просто взорвала разум системы импорта. Я могу представить, что есть способ заставить это работать из командной строки. Поскольку я относительно недавно начал программировать на Python, он вызывает у меня ностальгическое чувство работы с COM, но это немного менее увлекательно.


1

Мои 2 цента на это: pytest может потерпеть неудачу, если вы не используете виртуальные среды. Иногда это просто работает, иногда нет.

Следовательно, решение:

  • удалить pytest с помощью pip uninstall
  • создай свой венв
  • активируй свой Venv
  • pip установите путь к вашему проекту в редактируемом режиме, поэтому он будет рассматриваться pytest как модуль (в противном случае pytest не найдет ваш внутренний импорт). Для этого вам понадобится файл setup.py
  • установите свои пакеты, включая pytest
  • наконец, запустите свои тесты

Код, использующий Windows PowerShell:

pip uninstall pytest
python.exe -m venv my_env
.\my_env\Scripts\activate
(my_env) pip install -e .
(my_env) pip install pytest pytest-html pandas numpy

Тогда наконец

(my_env) pytest --html="my_testing_report.html"

Пример setup.py для pip install -e:

import setuptools

setuptools.setup(
    name='my_package',
    version='devel',
    author='erickfis',
    author_email='erickfis@gmail.com',
    description='My package',
    long_description='My gooood package',
    packages=setuptools.find_packages(),
    classifiers=[
        'Programming Language :: Python :: 3',
        'Operating System :: OS Independent',
    ],
    include_package_data=True
)

1

Я не согласен с сообщениями о том, что вы должны удалить любые __init__.pyфайлы. Вместо этого вы должны изменить файл sys.path.

Проведите эксперимент, при котором вы печатаете sys.pathпри обычном выполнении кода. Затем распечатайте sys.pathпри запуске кода через pytest. Я думаю, вы обнаружите разницу между этими двумя путями, поэтому pytest ломается.

Чтобы исправить это, вставьте путь из первого эксперимента в 0-й индекс второго.

Позвольте '/usr/exampleUser/Documents/foo'быть первым элементом print(sys.path)для эксперимента 1.

Ниже приведен код, который должен исправить вашу проблему:

import sys sys.path[0] = '/usr/exampleUser/Documents/foo'

Поместите это в начало файла перед фактическим оператором импорта.

Источник: Я сам имел дело с этим, и описанный выше процесс решил это.


1

Оставил все так же и просто добавил пустой тестовый файл в корневую папку .. Решил

Вот результаты, эта проблема меня какое-то время действительно беспокоила. Моя структура папок была

mathapp/
    - server.py  
    - configuration.py 
    - __init__.py 
    - static/ 
       - home.html  
tests/            
    - functional 
       - test_errors.py 
    - unit  
       - test_add.py

и pytest будет жаловаться на ModuleNotFoundError и дает СОВЕТ - убедитесь, что ваши тестовые модули / пакеты имеют допустимые имена Python.

Я представил файл фиктивного теста на том же уровне, что и каталог mathsapp и tests. В файле ничего не было. Теперь pytest не жалуется.

Результат без файла

$ pytest
============================= test session starts =============================
platform win32 -- Python 3.8.2, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\mak2006\workspace\0github\python-rest-app-cont
collected 1 item / 1 error

=================================== ERRORS ====================================
_______________ ERROR collecting tests/functional/test_func.py ________________
ImportError while importing test module 'C:\mainak\workspace\0github\python-rest-app-cont\tests\functional\test_func.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
tests\functional\test_func.py:4: in <module>
    from mathapp.service import sum
E   ModuleNotFoundError: No module named 'mathapp'
=========================== short test summary info ===========================
ERROR tests/functional/test_func.py
!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
============================== 1 error in 0.24s ===============================

Результаты с файлом

$ pytest
============================= test session starts =============================
platform win32 -- Python 3.8.2, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: C:\mak2006\workspace\0github\python-rest-app-cont
collected 2 items

tests\functional\test_func.py .                                          [ 50%]
tests\unit\test_unit.py .                                                [100%]

============================== 2 passed in 0.11s ==============================

это сработало для меня после долгого времени с этой проблемой. похоже, что pytest обрабатывает корень проекта как везде, где он находит первый тестовый файл? неужто это ошибка?
oooyaya

1

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

Пока вы просматриваете тестовый файл в PyCharm:

  1. Ctrl+ Shift+A
  2. Тип Edit Configurations
  3. Установите в PYTHONPATHразделе Среда> Переменные среды.

1

Просто поместите пустой conftest.pyфайл в корневой каталог проекта, потому что, когда pytestобнаруживает conftest.py, он изменяет sys.path, чтобы он мог импортировать данные из conftestмодуля. Общая структура каталогов может быть:

Root
├── conftest.py
├── module1
   ├── __init__.py
   └── sample.py
└── tests
    └── test_sample.py

1

В моем случае я работаю в контейнере, и, к сожалению, pytest имеет тенденцию использовать python2.7, а не мой предпочтительный интерпретатор python3.

В моем случае это сработало:

python3 -m pytest

Моя структура папок

/
app/
-module1.py
-module2.py
-tests/
--test_module1.py
--test_module2.py
requirements.txt
README.md

0

Возможно, Pytest не читает пакет как модуль Python, в то время как Python читает (вероятно, из-за проблем с путями). Попробуйте изменить каталог скрипта pytest или явно добавить модуль в свой PYTHONPATH.

Или может случиться так, что на вашем компьютере установлены две версии Python. Проверьте исходный код Python на наличие pytest и запускаемую оболочку python. Если они разные (например, Python 2 и 3), используйте, source activateчтобы убедиться, что вы запускаете pytest, установленный для того же питона, на котором установлен модуль.


0

Для тех, кто пробовал все и все еще получает ошибку, у меня есть работа.

В папке, где установлен pytest , перейдите в pytest-env .

Откройте pyvenv.cfg файл .

В файле измените include-system-site-packages с false на true .

home = /usr/bin
include-system-site-packages = true
version = 3.6.6

Надеюсь, это сработает. Не забудьте проголосовать за.


0

Если у вас уже есть файлы .pyc, попробуйте их удалить.

Сегодня я столкнулся с этой проблемой, вот что случилось:

сначала я запускаю pytest в mac (это сгенерирует файлы pyc), затем я запускаю контейнер докеров (ОС - alpine) с установленным каталогом проекта, а затем, когда я пытаюсь запустить pytest в контейнере, происходит ImportError. после очистки всех файлов pyc ошибок больше нет.

Надеюсь, это может быть полезно.


0

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


0

[Решено] Прежде чем перейти непосредственно к решению удаления / добавления __init__.py, мы также можем захотеть посмотреть, как выполняется импорт в ваших классах. На самом деле, я потерял день, играя, просто __init__.pyдумая, что это может быть проблемой :) Однако это было довольно информативно.

В моем случае это был неправильный способ вызова классов из одного класса Python в другой класс Python, который выбрасывал ImportError. Исправлен способ вызова классов / модулей, и это работало как шарм. Надеюсь, это поможет и другим.

И да, для подобной ошибки у нас могут быть разные решения в зависимости от того, как написан код. Лучше потратить больше времени на самостоятельную отладку. Полученный урок :) Удачного кодирования !!!


1
Не могли бы вы привести несколько примеров неправильного и правильного пути?
Lurifaxel

-1

Я поместил все свои тесты в папку с тестами и получал ту же ошибку. Я решил это, добавив init .py в эту папку следующим образом:

.
|-- Pipfile
|-- Pipfile.lock
|-- README.md
|-- api
|-- app.py
|-- config.py
|-- migrations
|-- pull_request_template.md
|-- settings.py
`-- tests
    |-- __init__.py <------
    |-- conftest.py
    `-- test_sample.py
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.