Masalah PATH dengan pytest 'ImportError: Tidak ada modul bernama YadaYadaYada'

231

Saya menggunakan easy_install untuk menginstal pytest pada mac dan mulai menulis tes untuk proyek dengan struktur file seperti:

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

dijalankan py.testsaat berada di direktori repo, semuanya berjalan seperti yang Anda harapkan

tetapi ketika saya mencoba hal yang sama di linux atau windows (keduanya memiliki pytest 2.2.3 pada mereka) itu menggonggong setiap kali hits impor pertama dari sesuatu dari jalur aplikasi saya. Katakan misalnyafrom app import some_def_in_app

Apakah saya perlu mengedit PATH saya untuk menjalankan py.test pada sistem ini? Adakah yang pernah mengalami ini?

MattoTodd
sumber
4
Ini cara untuk memperbaikinya dengan setuptools.
ederag
4
Silakan periksa @ pertanyaan jawaban dan pertimbangkan untuk mengubah jawaban yang Anda terima, jika SO memungkinkan setelah ini selama ini: jauh lebih baik!
Davide

Jawaban:

91

Ya, folder sumber tidak ada di jalur Python jika Anda cdke direktori tes.

Anda memiliki 2 pilihan:

  1. Tambahkan path secara manual ke file tes, sesuatu seperti ini:

    import sys, os
    myPath = os.path.dirname(os.path.abspath(__file__))
    sys.path.insert(0, myPath + '/../')
  2. Jalankan tes dengan env var PYTHONPATH=../.

Not_a_Golfer
sumber
11
kapan saya cdke direktori? saya berlari py.testdari root saya. kecuali saya salah dan maksud Anda sebagai pytest berjalan melalui folder saya
MattoTodd
jika itu cdmasalah, tidakkah saya akan memukulnya juga di mac?
MattoTodd
Oh, saya salah membaca dan berpikir itu tidak berfungsi dari direktori tes. tetap saja tipuan dalam saran 1 akan berhasil. Saya hanya menggunakan Linux jadi saya tidak bisa menjelaskan perilaku di OS lain.
Not_a_Golfer
apakah Anda memiliki impor seperti itu di semua file test.py Anda?
MattoTodd
4
ya, tetapi struktur direktori saya biasanya sedikit berbeda - saya biasanya menyimpan / src dan / test di bawah direktori root.
Not_a_Golfer
275

Saya tidak yakin mengapa py.test tidak menambahkan direktori saat ini di PYTHONPATH itu sendiri, tapi ini solusinya (akan dieksekusi dari root repositori Anda):

python -m pytest tests/

Ini berfungsi karena Python menambahkan direktori saat ini di PYTHONPATH untuk Anda.

Apteryx
sumber
2
Diperlukan untuk menulis ulang impor relatif ke yang absolut, jika Anda memiliki kode untuk menjalankan aplikasi bukan pada level, tempat Anda menjalankan perintah. Sebagai contoh: project/test/all-my-testsdan project/src/app.pydan karena perubahan itu, seseorang perlu memanggil yang app.pytidak langsung menggunakan __main__.pyfile project/src, sehingga seseorang dapat menggunakan panggilan python -m src. Hal-hal yang cukup berantakan sejauh yang saya tahu.
Zelphir Kaltstahl
3
@Zelphir: Menggunakan impor absolut adalah praktik yang disarankan. Habnabit's memiliki artikel bagus tentang pengemasan praktik terbaik: blog.habnab.it/blog/2013/07/21/python-packages-and-you , dan PEP8 mengatakan bahwa "impor relatif implisit tidak boleh digunakan dan telah dihapus dengan Python 3. " Lihat: python.org/dev/peps/pep-0008 .
Apteryx
1
@Apteryx Maksudmu "project-absolute", kan? Karena hal-hal seperti /home/user/dev/projectxyz/src ...akan sangat buruk dan tidak berjalan di komputer lain dalam banyak kasus. Saya pikir apa yang saya maksudkan adalah, bahwa saya harus selalu menulis seluruh proyek root ke lintasan modul bahkan jika modul ada di folder yang sama dengan file yang dijalankan. Saya tidak tahu bahwa ini dianggap praktik terbaik, jadi itu sedikit informasi yang berguna, terima kasih. Saya setuju dengan sebagian besar dari pep8, meskipun masih belum sempurna.
Zelphir Kaltstahl
1
@ Alpphir, ya, itulah yang saya maksud. Saya percaya istilah impor absolut dalam Python selalu merujuk ke "project-absolute". Lihat: python.org/dev/peps/pep-0328/#rationale-for-absolute-import . Bahkan, saya cukup yakin Anda tidak dapat mengimpor dari lokasi jalur absolut acak, setidaknya menggunakan mekanisme "impor" default.
Apteryx
4
Saya telah menambahkan __init__.pydalam tes, yang memecahkan masalah. Sekarang saya bisa menggunakanpytest
Kiran Kumar Kotari
154

conftest larutan

Solusi yang paling tidak invasif adalah menambahkan file kosong bernama conftest.pydalam repo/direktori:

$ touch repo/conftest.py

Itu dia. Tidak perlu menulis kode khusus untuk mengatur sys.pathatau mengingat untuk menyeret PYTHONPATH, atau menempatkan __init__.pyke dirs di tempat yang tidak seharusnya.

Direktori proyek sesudahnya:

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

Penjelasan

pytestmencari conftestmodul pada koleksi tes untuk mengumpulkan kait dan perlengkapan khusus, dan untuk mengimpor objek kustom dari mereka, pytestmenambahkan direktori induk conftest.pykesys.path (dalam hal ini repodirektori).

Struktur proyek lainnya

Jika Anda memiliki struktur proyek lain, tempatkan conftest.pydirektori dir paket (yang berisi paket tetapi bukan paket itu sendiri, jadi tidak mengandung __init__.py), misalnya:

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

src tata letak

Meskipun pendekatan ini dapat digunakan dengan srctata letak (tempat conftest.pydi srcdir):

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

waspadalah bahwa menambahkan srcuntuk PYTHONPATHmengurangi arti dan manfaat dari srctata letak! Anda akan berakhir dengan menguji kode dari repositori dan bukan paket yang diinstal. Jika Anda perlu melakukannya, mungkin Anda tidak perlu srcdir sama sekali.

Ke mana harus pergi dari sini

Tentu saja, conftestmodul bukan hanya beberapa file untuk membantu penemuan kode sumber; di situlah semua penyempurnaan spesifik proyek dari pytestkerangka kerja dan penyesuaian suite pengujian Anda terjadi. pytestmemiliki banyak informasi tentang conftestmodul yang tersebar di seluruh dokumen mereka ; mulai dengan conftest.py: plugin per-direktori lokal

Juga, SO memiliki pertanyaan yang sangat baik pada conftestmodul: Dalam py.test, apa gunanya file conftest.py?

hoefling
sumber
2
@ aaa90210 walaupun saya tidak dapat mereproduksi masalah Anda (mengimpor dari conftest dalam direktori root berfungsi pada level apa pun), Anda tidak boleh mengimpor dari file conftest karena itu adalah nama yang dicadangkan pytestdan sangat disarankan untuk tidak melakukannya. Dengan melakukan itu, Anda menanam benih untuk kesalahan di masa depan. Buat modul lain bernama utils.pydan tempatkan kode untuk digunakan kembali dalam tes di sana.
hoefling
4
Jempolan! Ini adalah satu-satunya solusi yang berfungsi dengan baik untuk saya.
130
4
harus benar-benar menjadi jawaban yang diterima - terima kasih!
Martin Peck
2
Logikanya, conftest.pybukan milik kode aplikasi dan, imo, menempatkannya di bawah src/tidak benar.
Nik O'Lai
2
Jawaban ini harus berupa tajuk yang tetap pada SO. Terima kasih banyak.
Rigoberta Raviolini
119

Saya memiliki masalah yang sama. Saya memperbaikinya dengan menambahkan __init__.pyfile kosong ke testsdirektori saya .

Aron Curzon
sumber
77
Perhatikan bahwa ini TIDAK direkomendasikan oleh 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
Saya datang ke sini dengan pertanyaan yang sama dan menemukan menghapus __init__.pydari direktori tes saya menyelesaikannya untuk saya.
101
3
@ mafro saya tidak melihat masalah? Tes tidak harus kode yang dapat diimpor, mereka ditemukan oleh pelari tes Anda. Hanya kode UNTUK DIUJI yang harus menjadi paket / modul yang diinstal, bukan tes.
K.-Michael Aye
5
Menambahkan __init__.pysub-direktori di test/membuat impor mutlak berfungsi untuk menjalankan tes tertentu di sub-direktori terhadap modul yang akan diinstal. Terima kasih.
Bryce Guinta
7
begitulah : doc.pytest.org/en/latest/goodpractices.html sangat mudah ditemukan dengan google.
K.-Michael Aye
46

Jalankan pytestsendiri sebagai modul dengan: python -m pytest tests

Stefano Messina
sumber
3
Ini tampaknya menjadi solusi yang baik, tetapi adakah yang bisa menjelaskan MENGAPA? Saya lebih suka memperbaiki penyebab yang mendasarinya daripada hanya menggunakan python -m pytesttanpa penjelasan selain "karena berfungsi"
Janne Enberg
4
Ini terjadi ketika hierarki proyek misalnya: package/src package/testsdan testsAnda mengimpor dari dalamnya src. Eksekusi sebagai modul akan mempertimbangkan impor sebagai absolut daripada relatif terhadap lokasi eksekusi.
Stefano Messina
1
Solusi ini membantu saya, terima kasih! Penyebabnya adalah karena konflik dalam versi Python. pytest test berfungsi untuk versi python sebelumnya. Dalam situasi saya, versi python saya adalah 3.7.1, tes pytest python -m bekerja tetapi tidak tes pytest.
Ruxi Zhang
1
Dari Pytest "Menjalankan pytest dengan python -m pytest [...] alih-alih pytest [...] menghasilkan perilaku yang hampir sama, kecuali bahwa panggilan sebelumnya akan menambahkan direktori saat ini ke sys.path."
Moad Ennagi
37

Anda dapat menjalankan dengan PYTHONPATH di root proyek

PYTHONPATH=. py.test

Atau gunakan pip instal sebagai impor yang dapat diedit

pip install -e .   # install package using setup.py in editable mode
Ford Guo
sumber
3
Itu tidak berfungsi untuk saya dengan testdirektori tidak dalam srcstruktur direktori dan panggilan dari direktori yang berisi keduanya testdan srcdirektori.
Zelphir Kaltstahl
21

Saya membuat ini sebagai jawaban untuk pertanyaan Anda dan kebingungan saya sendiri. Saya harap ini membantu. Perhatikan PYTHONPATH di baris perintah py.test dan di tox.ini.

https://github.com/jeffmacdonald/pytest_test

Khususnya: Anda harus memberi tahu py.test dan tahu di mana menemukan modul yang Anda sertakan.

Dengan py.test Anda bisa melakukan ini:

PYTHONPATH=. py.test

Dan dengan racun, tambahkan ini ke tox.ini Anda:

[testenv]
deps= -r{toxinidir}/requirements.txt
commands=py.test
setenv =
    PYTHONPATH = {toxinidir}
Jeff MacDonald
sumber
1
Bisakah Anda memberikan penjelasan singkat untuk proyek yang Anda tautkan?
JF Meier
1
Mungkin ini hanya saya, tetapi README pada proyek ini cukup rinci, dan komentar saya tentang stackoverflow mengatakan mengapa saya membuat repo.
Jeff MacDonald
5
Meskipun tidak sepenuhnya diperlukan, itu adalah kebijakan umum untuk memiliki konten utama dari jawaban dalam jawaban itu sendiri karena memastikan bahwa jawabannya dapat dipahami dalam x tahun dari sekarang ketika sumber daya yang ditautkan mungkin sudah lama hilang.
JF Meier
:) Baiklah. Itu internet untukmu.
Jeff MacDonald
9

Saya memiliki masalah yang sama di Labu.

Ketika saya menambahkan:

__init__.py

ke folder tes, masalah hilang :)

Mungkin aplikasi tidak dapat mengenali tes folder sebagai modul

pengguna13037517
sumber
8

Saya memperbaikinya dengan menghapus tingkat atas __init__.pydi folder induk sumber saya.

Gonzalo
sumber
1
Memperbaikinya untukku. Adakah yang bisa menjelaskan hal ini?
Aboger
ini di sini memperbaikinya untuk saya juga. pasti akan senang melihat penjelasan untuk ini jika ada yang memilikinya
king_wayne
saya menambahkan init .py tetapi masih menghadapi masalah yang sama tetapi solusi ini juga berhasil untuk saya .. alasannya tolong?
Abhijit
7

Saya mulai mendapatkan ConftestImportFailure: ImportError('No module named ...kesalahan aneh ketika saya secara tidak sengaja menambahkan __init__.pyfile ke direktori src saya (yang seharusnya tidak menjadi paket Python, hanya sebuah wadah dari semua sumber).

jasko
sumber
3

Saya mendapatkan kesalahan ini karena sesuatu yang lebih sederhana (Anda bahkan bisa mengatakan sepele). Saya belum menginstal pytestmodul. Jadi sederhana apt install python-pytestmemperbaikinya untukku.

'pytest' akan terdaftar di setup.py sebagai dependensi pengujian. Pastikan Anda menginstal persyaratan pengujian juga.

craq
sumber
3

Saya punya masalah serupa. pytesttidak mengenali modul yang dipasang di lingkungan tempat saya bekerja.

Saya mengatasinya dengan juga menginstal pytestke lingkungan yang sama.

nocibambi
sumber
Meskipun saya menggunakan pytest dari dalam venv, saya juga menginstalnya secara global yang memberi saya kesalahan ini. Setelah menghapus versi global dan menginstal di dalam venv itu berhasil.
Markus Ressel
2

Bagi saya masalahnya tests.pydihasilkan oleh Django bersama dengan testsdirektori. Menghapus tests.pymasalah diselesaikan.

Paweł Mucha
sumber
2

Saya mendapatkan kesalahan ini karena saya menggunakan impor relatif yang salah. Dalam contoh OP, test_app.py harus mengimpor fungsi menggunakan mis

from repo.app import *

Namun secara bebas file __init__.py tersebar di sekitar struktur file, ini tidak berfungsi dan membuat jenis ImportError terlihat kecuali file dan file uji berada di direktori yang sama.

from app import *

Berikut ini contoh apa yang harus saya lakukan dengan salah satu proyek saya:

Inilah struktur proyek saya:

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

Untuk dapat mengakses activity_indicator.py dari test_activity_indicator.py saya perlu:

  • mulai test_activity_indicatory.py dengan impor relatif yang benar:
    from microbit.activity_indicator.activity_indicator import *
  • letakkan file __init__.py di seluruh struktur proyek:
    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
Oppy
sumber
0

Sangat sering tes terputus karena modul tidak dapat diimpor, Setelah penelitian, saya menemukan bahwa sistem melihat file di tempat yang salah dan kita dapat dengan mudah mengatasi masalah dengan menyalin file, berisi modul, di folder yang sama seperti yang dinyatakan, agar dapat diimpor dengan benar. Usulan solusi lain adalah mengubah deklarasi untuk impor dan menunjukkan MutPy jalur yang benar dari unit. Namun, karena fakta bahwa banyak unit dapat memiliki ketergantungan ini, artinya kita perlu melakukan perubahan juga dalam deklarasi mereka, kami lebih memilih untuk hanya memindahkan unit ke folder.

Baydaa
sumber
Ada jawaban lain yang memberikan pertanyaan OP, dan mereka diposting beberapa waktu lalu. Saat mengirim jawaban, pastikan Anda menambahkan solusi baru, atau penjelasan yang jauh lebih baik, terutama saat menjawab pertanyaan yang lebih lama. Terkadang lebih baik memposting komentar pada jawaban tertentu.
help-info.de
Sebagai tambahan untuk komentar dari @ help-info.de: Ini adalah tautan ke panduan ini untuk menjawab pertanyaan: stackoverflow.com/help/how-to-answer
tangan NOD
0

Menurut posting di Medium oleh Dirk Avery (dan didukung oleh pengalaman pribadi saya) jika Anda menggunakan lingkungan virtual untuk proyek Anda, maka Anda tidak dapat menggunakan instalasi pytest di seluruh sistem; Anda harus menginstalnya di lingkungan virtual dan menggunakannya.

Secara khusus, jika Anda menginstalnya di kedua tempat maka hanya menjalankan pytestperintah tidak akan berhasil karena akan menggunakan instalasi sistem. Seperti yang dijelaskan oleh jawaban lain, satu solusi sederhana adalah menjalankan python -m pytestalih-alih pytest; ini berfungsi karena menggunakan versi pytest lingkungan. Atau, Anda cukup menghapus instalan versi sistem dari pytest; setelah mengaktifkan kembali lingkungan virtual, pytestperintah harus bekerja.

Einhaender
sumber
Satu-satunya hal yang berhasil bagi saya sejauh ini adalah python -m pytest tests/.
Nik O'Lai
0

Saya memiliki masalah yang sama ketika mengikuti tutorial Flask dan saya menemukan jawabannya di Pytest resmi docs Ini pergeseran sedikit dari cara saya (dan saya pikir banyak orang lain) digunakan untuk melakukan hal-hal.

Anda harus membuat setup.pyfile di direktori root proyek Anda dengan setidaknya dua baris berikut:

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

di mana PACKAGENAME adalah nama aplikasi Anda. Maka Anda harus menginstalnya dengan pip:

pip install -e .

The -eflag mengatakan pip untuk intall paket di diedit atau "mengembangkan" mode. Jadi lain kali Anda menjalankannya pytestharus menemukan aplikasi Anda dalam standar PYTHONPATH.

Luis Lezcano Airaldi
sumber
0

Solusi saya:

buat conftest.pyfile di testdirektori yang berisi:

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

Ini akan menambahkan folder yang menarik ke jalur python tanpa memodifikasi setiap file uji , mengatur variabel env atau mengacaukan jalur absolut / relatif.

davide burba
sumber