pytest não pode importar módulo enquanto python pode


115

Estou trabalhando em um pacote em Python. Eu uso o virtualenv. Eu defino o caminho para a raiz do módulo em um caminho .pth em meu virtualenv, para que eu possa importar módulos do pacote enquanto desenvolvo o código e faço o teste (Pergunta 1: é uma boa maneira de fazer?). Isso funciona bem (aqui está um exemplo, este é o comportamento que desejo):

(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

No entanto, se tento usar o PyTest, recebo algumas mensagens de erro de importação:

(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

Estou um pouco confuso, parece que isso indica um erro de importação, mas Python funciona bem, então por que há um problema específico com o PyTest? Alguma sugestão de motivo / remédio (Questão 2)? Pesquisei no Google e estourou a pilha do erro 'ImportError: não é possível importar' para PyTest, mas os resultados que obtive estavam relacionados à falta do caminho do Python e solução para isso, o que não parece ser o problema aqui. Alguma sugestão?

Respostas:


118

Encontrou a resposta:

NÃO coloque um __init__.pyarquivo em uma pasta contendo TESTES se você planeja usar o pytest. Eu tinha um desses arquivos, excluí-lo resolveu o problema.

Na verdade, isso foi enterrado nos comentários da segunda resposta do problema do PATH com pytest 'ImportError: Nenhum módulo chamado YadaYadaYada', então não o vi, espero que tenha mais visibilidade aqui.


44
Engraçado. Eu tive o mesmo problema e tive que adicionar init .py à minha pasta de testes.
Ev.

5
Sim, esta não é uma solução geral (embora fosse no seu caso), para entender por que deveria ser lida: docs.pytest.org/en/latest/goodpractices.html#test-package-name
juan

1
Esta informação é ERRADA e enganosa! Depois de adicionar init .py à pasta de teste, tudo funcionou bem
Leonardo Ostan,

1
@LeonardoOstan pode ser errada para você, mas não significa que esta informação esteja errada em geral. No meu caso, resolveu o problema.
Desprit

80

Não posso dizer que entendo por que isso funciona, mas tive o mesmo problema e os testes funcionam bem se eu executar python -m pytest.

Estou em um virtualenv, com pytest também disponível globalmente:

(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
Também fez o trabalho para mim, a coisa é ,, ele é executado pela versão python definida em vez de seu v.env
Nebulosar

12
um motivo pode ser que python -m pytest [...]"também adicionará o diretório atual a sys.path."
menos

Tinha o mesmo no Windows 10, e executando python -m pytest resolveu
Duccio

Isso funcionou tão bem dentro do meu ambiente virtual que tive que executarpython3 -m pytest
Rishi Raj

Com base no comentário de @minusf, estou usando PYTHONPATH=.:./src pytestcomo alvo do make.
janeiro groth

29

Acabei de resolver isso removendo o __init__.py na raiz do meu projeto:

.
├── __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
A resposta aceita __init__.py file in a folder containing TESTSnão resolveu meu problema. Este funcionou. Acho que é por causa da hierarquia de arquivos.
smido

Eu removi o __init__.pyarquivo. Eu ainda estava enfrentando problemas. Adicionar o arquivo conftest.py ao diretório raiz funcionou para mim.
Vijay Sali

Eu esperaria que conftest.py estivesse em / tests, não na raiz
Aaron McMillin

Obter o arquivo conftest.py para o diretório raiz também corrigiu para mim. Não tem um arquivo init .py no diretório de testes
atualização de

2
Esta solução funcionou para mim, mas alguém sabe que isso causaria um erro de importação?
Aldo Okware

19

Eu tive o mesmo problema, mas por um motivo diferente dos mencionados:

Eu tinha o py.test instalado globalmente, enquanto os pacotes foram instalados em um ambiente virtual.

A solução foi instalar pytestno ambiente virtual. (No caso de seu shell fazer hashes de executáveis, como o Bash faz, usa hash -rou usa o caminho completo para py.test)


2
Acabei de perceber que tive o mesmo problema sorrateiro, usando anaconda. Esqueci de adicionar pytesto virtualenv criado por conda, mas pytestele está disponível no ambiente raiz do anaconda. Portanto, o pytest pode ser encontrado, mas nenhum pacote instalado no ambiente.
Overdrivr

1
Eu tive o mesmo problema. pytest foi instalado globalmente e não no virtualenv. pip3 install pytestdentro do virtualenv corrigiu o problema.
Ankit Singh

7

Este problema acontecerá se você tiver um tests.pyarquivo e uma pasta de testes com tests/__init__.py.

Durante a coleta, o pytest encontra a pasta, mas quando tenta importar os arquivos de teste da pasta, o tests.pyarquivo causará o problema de importação.

Para corrigir, basta remover o tests.pyarquivo e colocar todos os seus testes dentro da tests/pasta.

Para o seu caso específico, a correção será precisamente:

  • Remova o arquivo /home/zz/Desktop/GitFolders/rc/tests.py
  • Certifique-se de /home/zz/Desktop/GitFolders/rc/tests/__init__.pyestar presente

4

Tive um problema semelhante, exatamente o mesmo erro, mas uma causa diferente. Eu estava executando o código de teste muito bem, mas com uma versão antiga do módulo. Na versão anterior do meu código, uma classe existia, enquanto a outra não. Depois de atualizar meu código, devo ter executado o seguinte para instalá-lo.

sudo pip install ./ --upgrade

Ao instalar o módulo atualizado, a execução de pytest produziu os resultados corretos (porque eu estava usando a base de código correta).


1
Isso funcionou para mim! Meu módulo foi instalado ao mesmo tempo como uma biblioteca no contêiner do docker que eu estava usando para executar o pytest. Ao executar o interpretador python, ele encontraria o código atualizado, mas o pytest continuaria a encontrar o código como estava quando a biblioteca foi instalada pela primeira vez. A execução pip install ./ --upgradeatualizou a versão instalada do lib com o código mais recente e permitiu que o pytest também encontrasse essa versão mais recente.
FaustoW

4

No meu caso, o erro de importação ocorreu porque o pacote está apontando para outro pacote / diretório com o mesmo nome e seu caminho está um nível acima da pasta que eu realmente queria. Acho que isso também explica por que algumas pessoas precisam remover _ init _.py enquanto outras precisam adicionar novamente.

Acabei de colocar print(the_root_package.__path__)(depois import the_root_package) no pythonconsole e nos pytestscripts para comparar a diferença

CONCLUSÃO: Ao fazer isso python, o pacote que você importa pode ser diferente do pacote quando você executa pytest.


3

Instale os pacotes em seu ambiente virtual.
Em seguida, inicie um novo shell e crie seu ambiente virtual novamente.


1
Esse foi o meu problema: uma nova instalação sem recarregar a venv
congelado

2

A resposta acima não funciona para mim. Eu apenas resolvi anexando o caminho absoluto do módulo que não foi encontrado sys.pathna parte superior do test_xxx.py(seu módulo de teste), como:

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

1
Em vez de colocar essas linhas no topo do meu test_main.py, coloquei conftest.pyno meu diretório de teste e funcionou. Obrigado por fornecer uma solução programática, em vez de lixo do arquivo.
Cameron Hudson

2

Se estiver relacionado ao código python que foi originalmente desenvolvido em python 2.7 e agora migrado para python 3.x, provavelmente o problema está relacionado a um problema de importação.

por exemplo, ao importar um objeto de um arquivo: baseque está localizado no mesmo diretório, isso funcionará no python 2.x:

from base import MyClass

no python 3.x você deve substituir pelo basecaminho completo ou .base não fazer isso causará o problema acima. então tente:

from .base import MyClass

2

Eu estava enfrentando esse problema hoje e resolvi chamando python -m pytestda raiz do diretório do meu projeto.

Chamar pytestdo mesmo local ainda causava problemas.

Meu diretório de projeto é organizado como:

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

O módulo routesfoi importado no meu test_routes.pycomo:from server.routes.routes import Routes

Espero que ajude!


Obrigado pelo lembrete, eu tive que usar o truque no passado e ele está na documentação do pytest.
Jason R Stevens CFA

1

Outro caso especial:

Tive o problema de usar tox. Então meu programa funcionou bem, mas os testes de unidade via tox continuaram reclamando. Depois de instalar os pacotes (necessários para o programa), você precisa especificar adicionalmente os pacotes usados ​​nos testes de unidade no tox.ini

[testenv]
deps =
    package1
    package2 
...

1

Eu estava recebendo isso usando VSCode. Eu tenho um ambiente conda. Não acho que a extensão python VScode pudesse ver as atualizações que eu estava fazendo.

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:

Eu tive que correr pip install ./ --upgrade


Esse comando pip retorna um erro:Directory './' is not installable. Neither 'setup.py' nor 'pyproject.toml' found.
Derek

1

Edite seu conftest.py e adicione as seguintes linhas de código:

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

E se tentar executar o caso de teste através do terminal, use o seguinte exemplo:

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

NameError: name 'file' is not defined- a que arquivo deve ser igual?
Koshmaar

1

Mais uma grande vitória para o sistema de importação do Python. Acho que o motivo de não haver consenso é que o que funciona provavelmente depende do seu ambiente e das ferramentas que você está usando nele.

Estou usando isso do VS Code, no explorador de teste no Windows em um ambiente conda, Python 3.8.

A configuração que tenho que trabalhar é:

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

Sob essa configuração, o intellisense funciona, assim como a descoberta de teste.

Observe que originalmente tentei o seguinte, conforme recomendado aqui .

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

Não consegui encontrar uma maneira de fazer isso funcionar a partir do VS Code porque a srcpasta simplesmente explodiu o sistema de importação. Posso imaginar que há uma maneira de fazer isso funcionar a partir da linha de comando. Como um convertido relativamente novo para a programação Python, me dá uma sensação nostálgica de trabalhar com COM, mas sendo um pouco menos divertido.


1

Meus 2 centavos nisso: o pytest falhará ao acaso se você não estiver usando ambientes virtuais. Às vezes funciona, às vezes não.

Portanto, a solução é:

  • remover pytest com desinstalação pip
  • crie seu venv
  • ative seu venv
  • pip instale o caminho do seu projeto no modo editável, então ele será tratado pelo pytest como um módulo (caso contrário, o pytest não encontrará suas importações internas). Você precisará de um arquivo setup.py para isso
  • instale seus pacotes, incluindo pytest
  • finalmente, execute seus testes

O código, usando o 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

Então finalmente

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

Um exemplo de setup.py, para 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

Não concordo com as postagens que dizem que você deve remover todos os __init__.pyarquivos. Em vez disso, o que você deve fazer é alterar o sys.path.

Execute um experimento em que você imprime sys.pathao executar o código normalmente. Em seguida, imprima sys.pathenquanto executa o código via pytest. Acho que você vai descobrir que há uma diferença entre esses dois caminhos, por isso pytest é interrompido.

Para corrigir isso, insira o caminho do primeiro experimento no índice 0 do segundo.

Deixe '/usr/exampleUser/Documents/foo'ser o primeiro elemento de print(sys.path)para o experimento 1.

Abaixo está o código que deve corrigir o seu problema:

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

Coloque-o no início do arquivo, antes da declaração de importação real.

Fonte: Eu estava lidando com isso sozinho e o processo acima resolveu.


1

Manteve tudo igual e apenas adicionou um arquivo de teste em branco na pasta raiz. Resolvido

Aqui estão as descobertas, este problema realmente me incomodou por um tempo. Minha estrutura de pastas era

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

e pytest reclamaria com o ModuleNotFoundError e daria a HINT - certifique-se de que seus módulos / pacotes de teste tenham nomes Python válidos.

Apresentei um arquivo de teste simulado no mesmo nível que o mathsapp e o diretório de testes. O arquivo não continha nada. Agora pytest não reclama.

Resultado sem o arquivo

$ 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 com o arquivo

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

isso funcionou para mim depois de muito tempo com esse problema. parece que o pytest está tratando a raiz do projeto como onde quer que ele encontre o primeiro arquivo de teste? certamente isso é um bug?
oooyaya

1

Resolvi meu problema definindo as PYTHONPATHvariáveis ​​de ambiente para a configuração específica com a qual estou executando meus testes.

Enquanto você está visualizando o arquivo de teste no PyCharm:

  1. Ctrl+ Shift+A
  2. Tipo Edit Configurations
  3. Defina seu PYTHONPATHem Ambiente> Variáveis ​​de ambiente.

1

Simplesmente coloque um conftest.pyarquivo vazio no diretório raiz do projeto, porque quando pytestdescobre um conftest.py, ele modifica sys.path para que possa importar coisas do conftestmódulo. Uma estrutura de diretório geral pode ser:

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

1

Tive um problema semelhante e funcionou quando adicionei o __init__.pyarquivo no diretório de testes.


0

Pode ser que o Pytest não esteja lendo o pacote como um módulo Python enquanto o Python está (provavelmente devido a problemas de caminho). Tente alterar o diretório do script pytest ou adicionar o módulo explicitamente ao seu PYTHONPATH.

Ou pode ser que você tenha duas versões do Python instaladas em sua máquina. Verifique seu código-fonte Python para pytest e para o shell python que você executa. Se eles forem diferentes (ou seja, Python 2 vs 3), use source activatepara ter certeza de que está executando o pytest instalado para o mesmo python em que o módulo está instalado.


0

Para quem já tentou de tudo e ainda assim obteve erros, tenho uma solução alternativa.

Na pasta onde o pytest está instalado , vá para a pasta pytest-env .

Abra o arquivo pyvenv.cfg .

No arquivo, altere os pacotes de site do sistema de falso para verdadeiro .

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

Espero que funcione. Não se esqueça de votar.


0

Se você já tiver arquivos .pyc, tente excluí-los.

Hoje, encontro esse problema, aqui está o que aconteceu:

primeiro eu executo o pytest no mac (isso irá gerar arquivos pyc), então eu lanço um contêiner do docker (o sistema operacional é alpino), com o dir do projeto montado, e então quando tento executar o pytest no contêiner, ImportError acontece. depois de limpar todos os arquivos pyc, nenhum erro mais.

Espero que isso possa ser útil.


0

se você precisar de um arquivo init .py em sua pasta, faça uma cópia da pasta e exclua init .py naquele para executar seus testes, ele funciona para projetos locais. Se você precisa executar o teste regularmente, veja se você pode mover seu init .py para um arquivo separado.


0

[Resolvido] Antes de pular diretamente para a solução de remoção / adição __init__.py, também podemos querer ver como as importações são feitas em suas classes. Na verdade, perdi um dia brincando apenas __init__.pypensando que poderia ser o problema :) No entanto, isso foi bastante informativo.

No meu caso, era a maneira errada de chamar classes de uma classe Python para outra classe Python ImportError. Corrigido o modo como as classes / módulos eram chamados e funcionou perfeitamente. Espero que isso ajude outras pessoas também.

E sim, para erros semelhantes, podemos ter soluções diferentes dependendo de como o código é escrito. Melhor gastar mais tempo com a auto depuração. Lição aprendida :) Boa codificação !!!


1
Você poderia dar alguns exemplos da maneira errada e da maneira certa?
Lurifaxel

0

No meu caso, estou trabalhando em um contêiner e, infelizmente, o pytest tem a tendência de usar python2.7 em vez do interpretador python3 de minha escolha.

No meu caso, funcionou:

python3 -m pytest

Minha estrutura de pastas

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

-1

Coloquei todos os meus testes em uma pasta de testes e estava recebendo o mesmo erro. Resolvi isso adicionando um init .py nessa pasta, assim:

.
|-- 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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.