ModuleNotFoundError с pytest

Я хочу, чтобы мой папка с тестами отдельная был в моем коде приложения. Моя структура проекта такая

myproject/
  myproject/
    myproject.py
    moduleone.py
  tests/
    myproject_test.py

мой проект.py

from moduleone import ModuleOne

class MyProject(object)
....

мой проект_test.py

from myproject.myproject import MyProject
import pytest

...

Я использую myproject.myproject, так как я использую команду

python -m pytest

из корневого каталога проекта ./myproject/

Однако тогда импорт в этих модулях завершается с ошибкой

E ModuleNotFoundError: No module named 'moduleone'

Я использую Python 3.7 и прочитал, что начиная с 3.3 пустые файлы __init__ больше не нужны, что означает, что мой проект становится неявный пакет пространства имен

Тем не менее, я попытался добавить файл __init__.py в myproject/myproject/, а также попытался добавить файл conftest.py в myproject/, но ни один из них не работает.

У меня есть читать ответы, которые говорят путаться с дорожками, а затем проголосовали за комментарии в других вопросах, говоря не.

Каков правильный путь и что мне не хватает?

РЕДАКТИРОВАТЬ;

Возможно, это связано с тем, что я использовал requirements.txt для установки pytest с помощью pip. Может ли это быть связано? И если да, то как правильно установить pytest в этом случае?

Обновлено еще раз:

Один из путей в sys.path — это /usr/src/app/, который представляет собой том докера, связанный с /my/local/path/myproject/.

Должна ли громкость быть /my/local/path/myproject/myproject/ вместо этого?

Честно говоря, это будет война мнений, если что. Вы можете переместить тестовую папку в свою основную структуру и выполнить ее оттуда, и все будет работать как есть. Не нужно ничего менять, поскольку пути импорта будут актуальны. Кроме этого, вам нужно будет исправить путь в тестовых файлах, чтобы включить целевой каталог, и это было бы неплохо (мнение). Просто знайте, почему и что вы делаете.

Torxed 26.02.2019 23:21

Длинные комментарии. Вы также можете (в командной строке) добавить PYTHONPATH, чтобы включить целевой каталог. Это означает, что вам не придется манипулировать sys.path из любого из ваших скриптов, но вы получите обновленный путь при запуске теста. PYTHONPATH=./myproject python -m pytest как будто вы это сделали.

Torxed 26.02.2019 23:23

Из каталогов, которые вы перечислили в структуре проекта, какие (если есть) есть в вашем PYTHONPATH?

John Gordon 27.02.2019 01:01

@JohnGordon обновил вопрос новой информацией

myol 27.02.2019 11:05

Вы пытались добавить пустой в этом.py в каталог ./tests вместо каталога вашего проекта. Это может показаться странным, но стоит попробовать.

cli 27.05.2020 01:37
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
49
5
31 085
12
Перейти к ответу Данный вопрос помечен как решенный

Ответы 12

Обязательно включите . точку в $PYTHONPATH env var.

Используйте $ python -m site или этот фрагмент кода для отладки таких проблем:

import pprint
import sys
pprint.pprint(sys.path)

В вашем вопросе удалось использовать myproject на трех разных уровнях. По крайней мере, во время отладки вы можете использовать три разных имени, чтобы уменьшить возможную путаницу.

Таким образом, кажется, что sys.path должен включать каталог приложений, а не корневую папку проекта, содержащую каталог приложения и тестовый каталог.

Так что в моем случае /my/local/path/myproject/myproject/ должно было быть в sys.path, а не /my/local/path/myproject/.

Тогда я мог запустить pytest в /my/local/path/myproject/ (не нужно python -m pytest). Это означало, что модули внутри /myproject/myproject/ могли находить друг друга и тесты без какой-либо вложенности пространств имен.

Так выглядели мои тесты

 from moduleone import ModuleOne
 import pytest

 def test_fun():
     assert ModuleOne.example_func() == True

Тем не менее, похоже, что много ошибок, так что я понятия не имею, правильно ли это...

Я также столкнулся с этой проблемой и использую поэзию для управления зависимостями и direnv для переменных среды, специфичных для моего проекта. Обратите внимание, что я относительно новичок в Python, поэтому я не знаю, правильное ли это решение.

Вот весь мой файл .envrc:

layout_poetry() {
  if [[ ! -f pyproject.toml ]]; then
    log_error 'No pyproject.toml found.  Use `poetry new` or `poetry init` to create one first.'
    exit 2
  fi

  local VENV=$(poetry env list --full-path | cut -d' ' -f1)
  if [[ -z $VENV || ! -d $VENV/bin ]]; then
    log_error 'No created poetry virtual environment found.  Use `poetry install` to create one first.'
    exit 2
  fi
  VENV=$VENV/bin
  export VIRTUAL_ENV=$(echo "$VENV" | rev | cut -d'/' -f2- | rev)
  export POETRY_ACTIVE=1
  PATH_add "$VENV"
}

layout poetry
export PYTHONDONTWRITEBYTECODE=1
export PYTHONPATH = "$PWD/project_name"

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

Для этого конкретного вопроса последняя строка — это производитель денег.

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

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

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

и pytest будет жаловаться на ModuleNotFoundError.

Я представил тестовый файл на том же уровне, что и mathsapp и каталог с тестами. В файле ничего не было. Теперь 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 ==============================
Ответ принят как подходящий

Решение: используйте окружение PYTHONPATH. вар

PYTHONPATH=. pytest

Как уже упоминалось @J_H, вам нужно явно добавить корневой каталог вашего проекта, поскольку pytest добавляется только в sys.path каталоги, в которых находятся тестовые файлы (именно поэтому ответ @Mak2006 сработал).


Хорошая практика: используйте Makefile или другой инструмент автоматизации.

Если вы не хотите постоянно вводить эту длинную команду, один из вариантов — создать Makefile в корневом каталоге вашего проекта, например, следующим образом:

.PHONY: test
test:
    PYTHONPATH=. pytest

Что позволяет вам просто запустить:

make test

Другой распространенной альтернативой является использование какого-либо стандартного инструмента тестирования, такого как отравить.

Небольшое замечание: в make-файлах для отступов требуются табуляции, поэтому копирование вашего кода может не сработать, поскольку в нем используются пробелы.

SilverSlash 08.08.2021 06:21

Спасибо @SilverSlash! В исходном коде на самом деле используются табуляции, но на самом деле в ответе они отображаются как пробелы. Кто-нибудь знает, как это исправить?

Arthur Colombini Gusmão 09.08.2021 14:56

Я думаю, что это ограничение HTML и веб-браузеров, к сожалению.

Marcus Harrison 10.11.2021 20:01

Не уверен, что это решение было специфичным для моей проблемы, но я просто добавляю __init__.py в свою папку tests, и это решило проблему.

Это помогает, спасибо. Могу ли я узнать, почему он меняет поведение импорта pytest, добавляя в этом.py в папку тестов?

hui chen 24.05.2021 09:40

В моем случае я добавил __init__.py в свой тестовый каталог с этим внутри:

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

Код моего приложения находится на том же уровне, что и мой тестовый каталог.

Используя поэзию и pytest 5.4.3, у меня была следующая структура (некоторые папки/файлы были удалены для ясности):

структура проекта

.
├── my_app
│   ├── __init__.py
│   ├── main.py
│   ├── model.py
│   └── orm.py
├── poetry.lock
├── pyproject.toml
├── README.rst
└── tests
    ├── __init__.py
    ├── conftest.py
    ├── test_my_app.py
    └── utilities
        └── db_postgresql_inmemory.py

тесты/conftest.py

pytest_plugins = [
    "utilities.db_postgresql_inmemory",
]

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

ImportError: Error importing plugin "utilities.db_postgresql_inmemory": No module named 'utilities'

Ни один из других ответов не сработал для меня, поскольку я пытался добавить:

[me@linux ~/code/my_app]touch tests/utilities/__init__.py
[me@linux ~/code/my_app]touch ./test_blank.py

Я мог бы заставить импорт из conftest.py работать с УДАЛЕНИЕ обоими __init__.py файлами:

[me@linux ~/code/my_app]rm tests/utilities/__init__.py tests/__init__.py

В моем случае это потому, что я установил pytest на системном уровне, а не в своей виртуальной среде.

Вы можете проверить это по python -m pytest. Если вы видите ModuleNotFoundError: No module named 'pytest', значит ваш pytest находится на системном уровне.

Установите pytest, когда виртуальная среда активирована, это исправит.

В моем случае он установлен как на системном, так и на виртуальном уровне. Но работает только python3 -m pytest.

naisanza 16.01.2022 06:00

ДРУГОЕ ПРЕДЛОЖЕНИЕ

Смотрите этот ответ: https://stackoverflow.com/a/69691436/595305

Я столкнулся с проблемой, которую я решил

  • Установка pytest в корень моего проекта с помощью pip install pytest
  • Добавление пробела __init__.py в брате моего test_file.py, который я хотел выполнить.

В моем случае я создал отдельное приложение для тестирования __init__.py и conftest.py на одном уровне. После удаления __init__.py ошибка исчезла.

Кредит идет наqci-амос

Другие вопросы по теме