ModuleNotFoundError con pytest

7 minutos de lectura

avatar de usuario de myol
miol

Quiero mi carpeta de pruebas separada a mi código de aplicación. La estructura de mi proyecto es así.

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

miproyecto.py

from moduleone import ModuleOne

class MyProject(object)
....

miproyecto_prueba.py

from myproject.myproject import MyProject
import pytest

...

yo suelo myproject.myproject ya que uso el comando

python -m pytest

desde el directorio raíz del proyecto ./myproject/

Sin embargo, las importaciones dentro de esos módulos fallan con

E ModuleNotFoundError: ningún módulo llamado ‘moduleone’

Estoy ejecutando Python 3.7 y lo he leído desde 3.3, vacío __init__ los archivos ya no son necesarios, lo que significa que mi proyecto se convierte en un paquete de espacio de nombres implícito

Sin embargo, he intentado agregar un __init__.py presentar en myproject/myproject/ y también intenté agregar un conftest.py presentar en myproject/ pero tampoco funciona

He leído respuestas que dicen meterse con las rutas y luego voté comentarios positivos en otras preguntas que decían que no.

¿Cuál es la forma correcta y qué me estoy perdiendo?

EDITAR;

Posiblemente relacionado, usé un requirements.txt para instalar pytest usando pip. ¿Podría esto estar relacionado? Y si es así, ¿cuál es la forma correcta de instalar pytest en este caso?

EDITAR 2:

Uno de los caminos en sys.path es /usr/src/app/ que es un volumen docker alineado a /my/local/path/myproject/.

Si el volumen es /my/local/path/myproject/myproject/ ¿en cambio?

  • Honestamente, esto va a ser una guerra de opiniones en todo caso. Puede mover la carpeta de prueba a su estructura principal y ejecutarla desde allí, y podría funcionar tal como está. No necesitaría cambiar nada ya que las rutas de importación serían relevantes. Aparte de eso, necesitaría parchear la ruta en los archivos de prueba para incluir el directorio de destino, y no sería algo malo (opinión). Sólo sé por qué y qué estás haciendo.

    – torcido

    26 de febrero de 2019 a las 22:21

  • Comentarios largos. También podría (en su línea de comando) agregar el PYTHONPATH para incluir el directorio de destino. Lo que significa que no tendrías que manipular sys.path de cualquiera de sus scripts, pero obtendría una ruta actualizada al ejecutar la prueba. PYTHONPATH=./myproject python -m pytest como si lo hicieras.

    – torcido

    26 de febrero de 2019 a las 22:23


  • De los directorios que enumeró en la estructura del proyecto, que (si los hay) están en su PYTHONPATH?

    – John Gordon

    27 de febrero de 2019 a las 0:01

  • @JohnGordon actualizó la pregunta con nueva información

    – miol

    27 de febrero de 2019 a las 10:05

  • ¿Has probado a añadir el vacío? en eso.py al directorio ./tests en lugar del directorio de su proyecto. Puede sonar extraño, pero vale la pena intentarlo.

    – cli

    26 mayo 2020 a las 23:37

No estoy seguro si esta solución era específica para mi problema, pero simplemente agrego __init__.py para mi tests carpeta y eso resolvió el problema.

  • Esto hace el truco, gracias. ¿Puedo saber por qué cambia el comportamiento de importación de pytest agregando un en eso.py en la carpeta de pruebas?

    – hui-chen

    24 de mayo de 2021 a las 7:40


  • funcionó para mí también, sin embargo, ¿es esta una mala práctica?

    – Neeta

    2 de marzo a las 16:21

  • Mi tests carpeta ya tenía un __init__.py archivo, por lo que puedo confirmar que esta solución no es universal.

    – muad-dweeb

    4 de marzo a las 21:04

  • @huichen __init__.py le dice a Python que la carpeta es un módulo. Sin ella, la carpeta no es un módulo y, por lo tanto, Python no puede encontrar su nombre cuando se usa en import declaraciones.

    – theberzi

    6 de septiembre a las 7:35

Avatar de usuario de Arthur Colombini Gusmão
Arthur Colombini Gusmão

Solución: usa el PYTHONPATH env. variable

PYTHONPATH=. pytest

Como mencionó @J_H, debe agregar explícitamente el directorio raíz de su proyecto, ya que pytest solo se suma a sys.path directorios donde están los archivos de prueba (razón por la cual funcionó la respuesta de @Mak2006).


Buena práctica: use un Makefile o alguna otra herramienta de automatización

Si no desea escribir ese comando largo todo el tiempo, una opción es crear un Makefile en el directorio raíz de su proyecto con, por ejemplo, lo siguiente:

.PHONY: test
test:
    PYTHONPATH=. pytest

Lo que le permite simplemente ejecutar:

make test

Otra alternativa común es usar alguna herramienta de prueba estándar, como tóxico.

  • Solo una nota menor: los archivos MAKE requieren tabulaciones para la sangría, por lo que es posible que copiar y pegar su código no funcione ya que usa espacios.

    – Plata

    8 de agosto de 2021 a las 4:21

  • ¡Gracias @SilverSlash! El código fuente en realidad usa pestañas, pero, de hecho, se representa como espacios en la respuesta. ¿Alguien sabe cómo arreglar esto?

    – Arthur Colombini Gusmão

    9 de agosto de 2021 a las 12:56

  • Creo que es una limitación de HTML y navegadores web, desafortunadamente.

    –Marcus Harrison

    10 de noviembre de 2021 a las 19:01

  • Aleluya. ¿POR QUÉ?

    – tejer

    25 oct a las 21:24

Avatar de usuario de J_H
J H

Asegúrese de incluir . punto en el $PYTHONPATH var.

Usar $ python -m siteo este fragmento de código para depurar tales problemas:

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

Tu pregunta logró usar myproject en tres niveles diferentes. Al menos durante la depuración, es posible que desee utilizar tres nombres distintos para reducir la posible confusión.

En mi caso agregué un __init__.py a mi directorio de prueba con esto dentro:

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

El código de mi aplicación está al mismo nivel que mi directorio de prueba.

Mantuvo todo igual y solo agregó un archivo de prueba en blanco en la carpeta raíz. Resuelto

Aquí están los hallazgos, este problema realmente me molestó por un tiempo. Mi estructura de carpetas era

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

y pytest se quejaría con ModuleNotFoundError.

Introduje un archivo de prueba simulado al mismo nivel que la aplicación de matemáticas y el directorio de pruebas. El archivo no contenía nada. Ahora pytest no se queja.

Resultado sin el archivo

$ 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 ===============================

Resultados con el archivo

$ 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 ==============================

Avatar de usuario de Qin Heyang
qinheyang

En mi caso es porque instalé pytest en el nivel del sistema pero no en mi entorno virtual.

Puedes probar esto por python -m pytest. Si tú ves ModuleNotFoundError: No module named 'pytest' entonces tu pytest está a nivel del sistema.

Instalar pytest cuando se active el entorno virtual se solucionará esto.

Entonces parece que el sys.path tiene que incluir el directorio de la aplicación en lugar de la carpeta raíz del proyecto que contiene el directorio de la aplicación y el directorio de prueba.

entonces en mi caso /my/local/path/myproject/myproject/ tenía que estar en sys.path más bien que /my/local/path/myproject/.

Entonces podría correr pytest en /my/local/path/myproject/ (no necesitaba python -m pytest). Esto significó que los módulos dentro /myproject/myproject/ podrían encontrarse entre sí y las pruebas también sin anidar ningún espacio de nombres.

Así que mis pruebas parecían

 from moduleone import ModuleOne
 import pytest

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

Dicho esto, parece haber muchas trampasasí que no tengo idea si esto es correcto …

¿Ha sido útil esta solución?