Problema PERCORSO con pytest 'ImportError: nessun modulo chiamato YadaYadaYada'


231

Ho usato easy_install per installare Pytest su un Mac e ho iniziato a scrivere test per un progetto con una struttura di file simile a:

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

eseguito py.testnella directory repo, tutto si comporta come ci si aspetterebbe

ma quando provo la stessa cosa su Linux o Windows (entrambi hanno Pytest 2.2.3 su di loro) si abbaia ogni volta che colpisce la sua prima importazione di qualcosa dal mio percorso applicativo. Dì per esempiofrom app import some_def_in_app

Devo modificare il mio PATH per eseguire py.test su questi sistemi? Qualcuno l'ha sperimentato?


4
Ecco il modo per risolverlo con setuptools.
ederag,

4
Controlla la risposta di @hoefling e considera di cambiare quella accettata, se SO lo consente dopo così tanto tempo: molto meglio!
Davide,

Risposte:


91

Sì, la cartella di origine non si trova nel percorso di Python se ci si trova cdnella directory dei test.

Hai 2 scelte:

  1. Aggiungi il percorso manualmente ai file di test, in questo modo:

    import sys, os
    myPath = os.path.dirname(os.path.abspath(__file__))
    sys.path.insert(0, myPath + '/../')
  2. Esegui i test con env var PYTHONPATH=../.


11
quando sto cdpassando a una directory? sto correndo py.testdalla mia radice. a meno che non mi sbagli e tu intendi come il pytest cammina attraverso le mie cartelle
MattoTodd,

se fosse un cdproblema, non lo avrei colpito anche su Mac?
MattoTodd,

Oh, ho letto male e ho pensato che non funzionasse dalla directory dei test. il trucco nel suggerimento 1 funzionerebbe comunque. Uso solo Linux, quindi non posso spiegare il comportamento su altri sistemi operativi.
Not_a_Golfer

hai un'importazione del genere su tutti i tuoi file test.py?
MattoTodd,

4
sì, ma la mia struttura di directory è in genere leggermente diversa - di solito tengo / src e / test nella directory root.
Not_a_Golfer

276

Non sono sicuro del motivo per cui py.test non aggiunge la directory corrente nel PYTHONPATH stesso, ma ecco una soluzione alternativa (da eseguire dalla radice del repository):

python -m pytest tests/

Funziona perché Python aggiunge la directory corrente in PYTHONPATH per te.


2
Richiede di riscrivere le importazioni relative a quelle assolute, se si dispone del codice per l'esecuzione dell'applicazione non a livello, da cui si esegue il comando. Ad esempio: project/test/all-my-testse, a project/src/app.pycausa di tale modifica, è necessario chiamare app.pyindirettamente utilizzando un __main__.pyfile project/src, in modo da poter utilizzare la chiamata python -m src. Roba piuttosto disordinata per quanto posso dire.
Zelphir Kaltstahl,

3
@Zelphir: l'utilizzo di importazioni assolute è una pratica consigliata. Habnabit's ha un buon articolo sulle migliori pratiche di packaging: blog.habnab.it/blog/2013/07/21/python-packages-and-you e PEP8 afferma che "le importazioni relative implicite non dovrebbero mai essere utilizzate e sono state rimosse in Python 3." Vedi: python.org/dev/peps/pep-0008 .
Apteryx,

1
@Apteryx Intendi "progetto-assoluto" giusto? Perché cose del genere /home/user/dev/projectxyz/src ...sarebbero davvero brutte e non funzionerebbero su altre macchine nella maggior parte dei casi. Penso che intendevo dire che devo sempre scrivere l'intero root del progetto nel percorso del modulo anche se un modulo si trova nella stessa cartella dell'esecuzione del file. Non sapevo che questa è considerata la migliore pratica, quindi è utile un po 'di informazioni, grazie. Sono d'accordo con la maggior parte di pep8, anche se non è ancora perfetto.
Zelphir Kaltstahl,

1
@Zelphir, sì, questo è ciò che intendevo. Credo che il termine importazioni assolute in Python si riferisca sempre a "progetto-assoluto". Vedi: python.org/dev/peps/pep-0328/#rationale-for-absolute-imports . In effetti, sono abbastanza sicuro che non puoi importare da percorsi casuali, percorsi assoluti, almeno usando il meccanismo di "importazione" predefinito.
Apteryx,

4
Ho aggiunto dei __init__.pytest che hanno risolto il problema. Ora posso usarepytest
Kiran Kumar Kotari il

154

conftest soluzione

La soluzione meno invasiva è l'aggiunta di un file vuoto denominato conftest.pynella repo/directory:

$ touch repo/conftest.py

Questo è tutto. Non è necessario scrivere codice personalizzato per manipolare sys.patho ricordare di trascinarlo PYTHONPATHo posizionarlo __init__.pyin dir dove non appartiene.

La directory del progetto in seguito:

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

Spiegazione

pytestcerca i conftestmoduli per la raccolta di test per raccogliere ganci personalizzati e infissi, e al fine di importare gli oggetti personalizzati da loro, pytestaggiunge la directory padre della conftest.pyallasys.path (in questo caso la repodirectory).

Altre strutture di progetto

Se si dispone di un'altra struttura di progetto, posizionare il conftest.pynella directory root del pacchetto (quello che contiene i pacchetti ma non è un pacchetto stesso, quindi non contiene un __init__.py), ad esempio:

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

src disposizione

Sebbene questo approccio possa essere utilizzato con il srclayout (posizionare conftest.pynella srcdirectory):

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

attenzione che l'aggiunta srcper PYTHONPATHmitigare il significato e i vantaggi del srclayout! Si finirà con il test del codice dal repository e non del pacchetto installato. Se hai bisogno di farlo, forse non hai bisogno del srcdir.

Dove andare da qui

Naturalmente, i conftestmoduli non sono solo alcuni file per aiutare la scoperta del codice sorgente; è qui che si verificano tutti i miglioramenti specifici del progetto del pytestframework e la personalizzazione della suite di test. pytestha molte informazioni sui conftestmoduli sparsi nei loro documenti ; inizia con conftest.py: plugin locali per directory

Inoltre, SO ha un'ottima domanda sui conftestmoduli: in py.test, a che cosa servono i file conftest.py?


2
@ aaa90210 anche se non riesco a riprodurre il tuo problema (l'importazione da un file conft in una directory root funziona su qualsiasi livello), non dovresti mai importare da file conftest in quanto è un nome riservato per pytested è fortemente consigliato di non farlo. In questo modo, pianti semi per errori futuri. Crea un altro modulo chiamato utils.pye inserisci il codice per riutilizzarlo nei test lì.
hoefling

4
Pollice su! Questa è l'unica soluzione che funziona bene per me.
130

4
dovrebbe assolutamente essere la risposta accettata - grazie!
Martin Peck,

2
Logicamente, conftest.pynon appartiene al codice dell'applicazione e, imo, posizionarlo sotto src/non è corretto.
Nik O'Lai,

2
Questa risposta dovrebbe essere un'intestazione fissa su SO. Molte grazie.
Rigoberta Raviolini,

119

Ho avuto lo stesso problema. L'ho corretto aggiungendo un __init__.pyfile vuoto alla mia testsdirectory.


77
Nota che questo NON è raccomandato da 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
Sono venuto qui con la stessa domanda e __init__.pyho scoperto che la rimozione dalla mia directory dei test lo ha risolto per me.
101

3
@mafro non vedo il problema? I test non devono essere codice imprecisabile, ma vengono trovati dal tuo test runner. Solo il codice DA TESTARE dovrebbe essere un pacchetto / modulo installato, non i test.
K.-Michael Aye,

5
L'aggiunta di una __init__.pysottodirectory di test/fa funzionare l'importazione assoluta per l'esecuzione di test specifici in quella sottodirectory rispetto ai moduli da installare. Grazie.
Bryce Guinta,

7
ecco qua : doc.pytest.org/it/latest/goodpractices.html davvero facile da trovare con google.
K.-Michael Aye,

46

Esegui pytestse stesso come un modulo con: python -m pytest tests


3
Questa sembra essere una soluzione funzionante, ma qualcuno può spiegare PERCHÉ? Preferirei correggere la causa sottostante piuttosto che usare python -m pytestsenza una spiegazione diversa da "perché funziona"
Janne Enberg,

4
Ciò accade quando la gerarchia del progetto è ad esempio: package/src package/testse in testsimport da src. L'esecuzione come modulo considererà le importazioni come assolute rispetto alla posizione di esecuzione.
Stefano Messina,

1
Questa soluzione mi ha aiutato, grazie! La causa è stata a causa del conflitto nella versione di Python. test pytest funziona per la versione precedente di python. Nella mia situazione, la mia versione di Python è 3.7.1, i test di Python -m pytest funzionano ma non i test di Pytest.
Ruxi Zhang,

1
Da Pytest "L'esecuzione di pytest con python -m pytest [...] anziché pytest [...] produce un comportamento quasi equivalente, tranne per il fatto che la prima chiamata aggiungerà la directory corrente a sys.path."
Moad Ennagi,

37

È possibile eseguire con PYTHONPATH nella radice del progetto

PYTHONPATH=. py.test

Oppure usa pip install come importazione modificabile

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

3
Ciò non ha funzionato per me con una testdirectory non nella srcstruttura delle directory e chiamata dalla directory contenente sia teste che srcdirectory.
Zelphir Kaltstahl,

21

L'ho creato come risposta alla tua domanda e alla mia confusione. Spero possa essere d'aiuto. Presta attenzione a PYTHONPATH sia nella riga di comando py.test che in tox.ini.

https://github.com/jeffmacdonald/pytest_test

In particolare: devi dire a py.test e tox dove trovare i moduli che stai includendo.

Con py.test puoi farlo:

PYTHONPATH=. py.test

E con tox, aggiungi questo al tuo tox.ini:

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

1
Potresti dare una breve spiegazione per il progetto che hai collegato?
JF Meier,

1
Forse sono solo io, ma il README sul progetto è piuttosto dettagliato e il mio commento su StackOverflow dice perché ho creato il repository.
Jeff MacDonald,

5
Sebbene non sia strettamente necessario, è una prassi normale avere il contenuto principale di una risposta nella risposta stessa perché garantisce che la risposta sia comprensibile tra x anni da quando la risorsa collegata potrebbe essere sparita da tempo.
JF Meier,

:) Oh bene. Questo è Internet per te.
Jeff MacDonald,

9

Ho avuto lo stesso problema in Flask.

Quando ho aggiunto:

__init__.py

nella cartella test, il problema è scomparso :)

Probabilmente l'applicazione non è riuscita a riconoscere i test delle cartelle come modulo


8

L'ho risolto rimuovendo il livello principale __init__.pynella cartella principale delle mie fonti.


1
Risolto il problema per me. Qualcuno può spiegare questo?
aboger

questo proprio qui l'ha risolto anche per me. sicuramente mi piacerebbe vedere una spiegazione per questo se qualcuno ce l'ha
king_wayne,

ho aggiunto init .py ma continuavo a riscontrare gli stessi problemi ma questa soluzione ha funzionato anche per me .. motivo per favore?
Abhijit,

7

Ho iniziato a ricevere strani ConftestImportFailure: ImportError('No module named ...errori quando avevo accidentalmente aggiunto il __init__.pyfile alla mia directory src (che non doveva essere un pacchetto Python, solo un contenitore di tutti i sorgenti).


3

Stavo ottenendo questo errore a causa di qualcosa di ancora più semplice (si potrebbe anche dire banale). Non avevo installato il pytestmodulo. Quindi un semplice apt install python-pytestrisolto per me.

'pytest' sarebbe stato elencato in setup.py come dipendenza di test. Assicurati di installare anche i requisiti di prova.


3

Ho avuto un problema simile. pytestnon ho riconosciuto un modulo installato nell'ambiente in cui stavo lavorando.

L'ho risolto installando anche pytestnello stesso ambiente.


Anche se stavo usando Pytest dall'interno di un Venv, l'ho installato anche a livello globale, il che mi ha dato questo errore. Dopo aver disinstallato la versione globale e installato all'interno di Venv, ha funzionato.
Markus Ressel il

2

Per me il problema è stato tests.pygenerato da Django insieme alla testsdirectory. La rimozione ha tests.pyrisolto il problema.


2

Ho ricevuto questo errore poiché ho utilizzato le importazioni relative in modo errato. Nell'esempio OP, test_app.py dovrebbe importare funzioni usando ad es

from repo.app import *

Tuttavia, i file __init__.py sono sparsi liberamente nella struttura del file, questo non funziona e crea il tipo di ImportError visto a meno che i file e i file di test non si trovino nella stessa directory.

from app import *

Ecco un esempio di cosa ho avuto a che fare con uno dei miei progetti:

Ecco la mia struttura del progetto:

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

Per poter accedere a activity_indicator.py da test_activity_indicator.py avevo bisogno di:

  • avvia test_activity_indicatory.py con l'importazione relativa corretta:
    from microbit.activity_indicator.activity_indicator import *
  • inserisci i file __init__.py in tutta la struttura del progetto:
    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

Molto spesso i test sono stati interrotti a causa dell'impossibilità di importare il modulo. Dopo la ricerca, ho scoperto che il sistema sta guardando il file nel posto sbagliato e possiamo facilmente superare il problema copiando il file, contenente il modulo, in la stessa cartella indicata, per essere correttamente importata. Un'altra proposta di soluzione sarebbe quella di modificare la dichiarazione per l'importazione e mostrare a MutPy il percorso corretto dell'unità. Tuttavia, a causa del fatto che più unità possono avere questa dipendenza, il che significa che è necessario eseguire il commit delle modifiche anche nelle loro dichiarazioni, preferiamo semplicemente spostare l'unità nella cartella.


Esistono altre risposte che forniscono la domanda del PO e sono state pubblicate qualche tempo fa. Quando pubblichi una risposta, assicurati di aggiungere una nuova soluzione o una spiegazione sostanzialmente migliore, specialmente quando rispondi a domande più vecchie. A volte è meglio pubblicare un commento su una risposta particolare.
help-info.de

Come aggiunta al commento di @ help-info.de: ecco il link alla guida per rispondere alle domande: stackoverflow.com/help/how-to-answer
la mano di NOD

0

Secondo un post su Medium di Dirk Avery (e supportato dalla mia esperienza personale) se stai usando un ambiente virtuale per il tuo progetto, non puoi utilizzare un'installazione di pytest a livello di sistema; devi installarlo nell'ambiente virtuale e usare quell'installazione.

In particolare, se lo hai installato in entrambi i posti, semplicemente l'esecuzione del pytestcomando non funzionerà perché utilizzerà l'installazione di sistema. Come hanno descritto le altre risposte, al python -m pytestposto di eseguire una soluzione semplice pytest; funziona perché utilizza la versione di pytest dell'ambiente. In alternativa, puoi semplicemente disinstallare la versione di pytest del sistema; dopo aver riattivato l'ambiente virtuale il pytestcomando dovrebbe funzionare.


L'unica cosa che ha funzionato per me finora è stata python -m pytest tests/.
Nik O'Lai,

0

Stavo avendo lo stesso problema quando seguivo il tutorial di Flask e ho trovato la risposta sui documenti ufficiali di Pytest È un po ' diverso dal modo in cui io (e penso che molti altri) sono abituato a fare le cose.

Devi creare un setup.pyfile nella directory principale del tuo progetto con almeno le seguenti due righe:

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

dove PACKAGENAME è il nome della tua app. Quindi devi installarlo con pip:

pip install -e .

Il -eflag dice a pip di installare il pacchetto in modalità modificabile o "sviluppo". Quindi la prossima volta che esegui pytest, dovrebbe trovare la tua app nello standard PYTHONPATH.


0

La mia soluzione:

crea il conftest.pyfile nella testdirectory contenente:

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

Ciò aggiungerà la cartella di interesse al percorso Python senza modificare tutti i file di test , impostando la variabile env o inviando messaggi con percorsi assoluti / relativi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.