pytestのPATH問題「ImportError:YadaYadaYadaという名前のモジュールはありません」


231

easy_installを使用してMacにpytestをインストールし、次のようなファイル構造を持つプロジェクトのテストの作成を開始しました。

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

py.testrepoディレクトリで実行すると、すべてが期待どおりに動作します

しかし、LinuxまたはWindows(どちらもpytest 2.2.3がインストールされています)で同じことを試みると、アプリケーションパスから何かの最初のインポートにヒットするたびに吠えます。たとえば言うfrom app import some_def_in_app

これらのシステムでpy.testを実行するには、PATHを編集する必要がありますか?誰かがこれを経験しましたか?


4
ここでは setuptoolsので、それを修正する方法があります。
ederag

4
@hoeflingの回答を確認し、SOがこの長い期間後に許可する場合は、受け入れたものを変更することを検討してください。
Davide

回答:


91

はい、cdtestsディレクトリに移動した場合、ソースフォルダーはPythonのパスにありません。

2つの選択肢があります。

  1. 次のようなパスをテストファイルに手動で追加します。

    import sys, os
    myPath = os.path.dirname(os.path.abspath(__file__))
    sys.path.insert(0, myPath + '/../')
  2. env varを使用してテストを実行しますPYTHONPATH=../


11
いつcdディレクトリに移動しますか?私はpy.test自分のルートから実行しています。pytestが私のフォルダーをウォークスルーするときに、私が間違っているのではない限り
MattoTodd 2012

それがcd問題だったら、Macでもヒットしませんか?
MattoTodd 2012

ああ、私は誤解して、testsディレクトリからは機能しないと思いました。それでも提案1のトリックは機能します。私はLinuxのみを使用しているため、他のOSでの動作を説明できません。
Not_a_Golfer 2012

すべてのtest.pyファイルにそのようなインポートがありますか?
MattoTodd 2012

4
はい、しかし私のディレクトリ構造は通常少し異なります-私は通常/ srcと/ testをルートディレクトリの下に置いています。
Not_a_Golfer 2012

275

py.testがPYTHONPATH自体に現在のディレクトリを追加しない理由はわかりませんが、回避策があります(リポジトリのルートから実行します)。

python -m pytest tests/

PythonがPYTHONPATHに現在のディレクトリを追加するため、これは機能します。


2
コマンドを実行するレベルではなく、アプリケーションを実行するためのコードがある場合は、相対インポートを絶対インポートに書き換える必要があります。例:project/test/all-my-testsそしてproject/src/app.py、その変更のため、でファイルapp.pyを使用して間接的に呼び出す必要があるため、呼び出しを使用できます。私の知る限りかなり厄介なもの。__main__.pyproject/srcpython -m src
Zelphir Kaltstahl 2016

3
@Zelphir:絶対インポートを使用することをお勧めします。Habnabit'sには、パッケージのベストプラクティスに関する優れた記事があります:blog.habnab.it/blog/2013/07/21/python-packages-and-you、そしてPEP8は、「暗黙的な相対インポートは決して使用すべきではなく、Pythonでは削除されるべきだと述べています3.」python.org/dev/peps/pep-0008を参照してください。
Apteryx 2016年

1
@Apteryx「プロジェクト絶対」という意味ですか?のようなものだから/home/user/dev/projectxyz/src ...は、たいていの場合、他のマシンでは実行できず、本当に悪いでしょう。モジュールがファイルの実行と同じフォルダーにある場合でも、プロジェクト全体のルートを常にモジュールパスに書き込む必要があるということです。これがベストプラクティスと見なされていることを知りませんでした。まだ完全ではありませんが、私はほとんどのpep8に同意します。
Zelphir Kaltstahl 2016年

1
@ゼルファイア、はい、それが私が意味したことです。Pythonでの絶対インポートという用語は、常に「プロジェクト絶対」を指していると思います。参照:python.org/dev/peps/pep-0328/#rationale-for-absolute-imports。実際、少なくともデフォルトの「インポート」メカニズムを使用して、ランダムな絶対パスの場所からインポートすることはできません。
Apteryx 2016年

4
__init__.py問題を解決したテストを追加しました。今すぐ使用できますpytest
Kiran Kumar

154

conftest 解決

最も侵襲性の低いソリューションはconftest.pyrepo/ディレクトリに名前が付けられた空のファイルを追加することです。

$ touch repo/conftest.py

それでおしまい。をマングルするためのカスタムコードを記述しsys.pathたり、ドラッグPYTHONPATHしたり配置したりすることを覚える必要はありません。__init__.py、それが属していないディレクトリにし。

その後のプロジェクトディレクトリ:

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

説明

pytestconftestテストコレクションでモジュールを探してカスタムフックとフィクスチャを収集し、それらからカスタムオブジェクトをインポートします。pytestの親ディレクトリを追加conftest.pyするsys.path(この場合、repoディレクトリ)。

その他のプロジェクト構造

他のプロジェクト構造がある場合conftest.pyは、パッケージルートディレクトリ(パッケージを含むがパッケージ自体ではないため、__init__.py、を)に配置します。次に例を示します。

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

src レイアウト

このアプローチはsrcレイアウトで使用できますconftest.pyが、src DIR):

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

を追加srcするPYTHONPATHことの意味と利点を軽減することに注意してくださいsrcレイアウトの。インストールされたパッケージではなく、リポジトリからコードをテストすることになります。あなたがそれをする必要があるなら、多分あなたはまったくsrcディレクトリを必要としません。

ここから先

もちろん、conftestモジュールはソースコードの発見に役立つ単なるファイルではありません。ここで、pytestフレームワークのプロジェクト固有のすべての拡張とテストスイートのカスタマイズが行われます。ドキュメント全体に散在するモジュールpytestに関する多くの情報がありconftestます。で始まる:ローカルのディレクトリごとのプラグインconftest.py

また、SOはconftestモジュールに関して優れた質問をしています。py.testでは、conftest.pyファイルの使用法は何ですか?


2
@ aaa90210私はあなたの問題を再現することはできませんが(ルートディレクトリのconftestからのインポートはどのレベルでも機能します)、conftestファイルからはインポートしpytestないでください。そうすることで、将来のエラーに備えて種をまきます。という名前の別のモジュールを作成しutils.py、コードをテストで再利用するために配置します。
1

4
いいぞ!これが私にとってうまくいく唯一の解決策です。

4
絶対に受け入れられる答えでなければなりません-ありがとうございます!
マーティンペック

2
論理的にconftest.pyは、アプリケーションコードに属しておらず、その下に置くことsrc/は正しくありません。
Nik O'Lai

2
この回答は、SOの固定ヘッダーである必要があります。どうもありがとう。
Rigoberta Raviolini

119

私も同じ問題を抱えていました。空の__init__.pyファイルをtestsディレクトリに追加して修正しました。


77
これは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
私は同じ質問でここに来て__init__.py、testsディレクトリから削除すると解決しました。
101

3
@mafro問題が発生しませんか?テストはインポート可能なコードである必要はありません。テストランナーによって検出されます。テストされるコードだけがインストールされたパッケージ/モジュールであって、テストではないはずです。
K.-Michael Aye 2015年

5
__init__.pyサブディレクトリにtest/を追加すると、インストールされるモジュールに対してそのサブディレクトリで特定のテストを実行するための絶対インポートが機能します。ありがとう。
ブライスギンタ2016

7
そこに行く:doc.pytest.org/en/latest/goodpractices.html googleで本当に簡単に見つけることができます。
K.-Michael Aye 2017年

46

pytest自分自身をモジュールとして実行します: python -m pytest tests


3
これは実用的な解決策のようですが、誰でもなぜ説明できますか?私はpython -m pytest「それが機能するから」以外の説明なしで単に使用するよりも根本的な原因を修正したい
ジャンヌ・エンバーグ

4
これは、たとえばプロジェクト階層が次の場合に発生package/src package/teststestsますsrc。モジュールとして実行すると、インポートは実行場所を基準にしたものよりも絶対的なものと見なされます。
Stefano Messina

1
この解決策は私に役立ちました、ありがとう!この原因は、Pythonバージョンの競合が原因でした。pytestテストは以前のバージョンのpythonで動作します。私の状況では、私のpythonバージョンは3.7.1です。python-m pytestテストは機能しますが、pytestテストは機能しません。
Ruxi Zhang

1
Pytestから「pytest [...]ではなくpython -m pytest [...]でpytestを実行すると、前の呼び出しで現在のディレクトリがsys.pathに追加されることを除いて、ほぼ同等の動作が得られます。」
Moad Ennagi

37

プロジェクトのルートでPYTHONPATHを使用して実行できます

PYTHONPATH=. py.test

または、pip installを編集可能なインポートとして使用します

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

3
ディレクトリ構造にtestないsrcディレクトリを使用していて、testsrcディレクトリの両方を含むディレクトリから呼び出すと、それはうまくいきませんでした。
Zelphir Kaltstahl 2016年

21

私はこれをあなたの質問と私自身の混乱への答えとして作成しました。お役に立てば幸いです。py.testコマンドラインとtox.iniの両方でPYTHONPATHに注意してください。

https://github.com/jeffmacdonald/pytest_test

具体的には、py.testとtoxに、含めるモジュールの場所を伝える必要があります。

py.testでこれを行うことができます:

PYTHONPATH=. py.test

そしてtoxを使用して、これをtox.iniに追加します。

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

1
リンクしたプロジェクトについて簡単に説明してください。
JF Meier

1
多分それは私だけかもしれませんが、プロジェクトのREADMEはかなり詳細であり、stackoverflowに関する私のコメントは、なぜ私がリポジトリを作成したかを述べています。
ジェフマクドナルド2016

5
厳密に必要なわけではありませんが、リンクされたリソースが長くなくなる可能性があるx年後に回答を理解できるようにするため、回答自体に回答の主な内容を含めることが通常のポリシーです。
JF Meier

:) しかたがない。それはあなたのためのインターネットです。
ジェフマクドナルド

9

Flaskでも同じ問題が発生しました。

追加したとき:

__init__.py

テストフォルダに、問題が消えました:)

おそらくアプリケーションはフォルダテストをモジュールとして認識できませんでした


8

__init__.pyソースの親フォルダーの最上位を削除して修正しました。


1
私のために修正しました。誰かがこれを説明できますか?
不正行為者、

これもここで修正しました。誰かがこれを持っているなら、間違いなくこれについての説明を見たいと
思い

私はinit .pyを追加しましたが、同じ問題に直面していましたが、この解決策もうまくいきました。理由は?
Abhijit

7

ConftestImportFailure: ImportError('No module named ...が誤って__init__.pyファイルをsrcディレクトリ(Pythonパッケージではなく、すべてのソースのコンテナーではない)に追加したときに、奇妙なエラーが発生し始めました。


3

私はこのエラーをもっと単純なもののために受け取りました(あなたは些細なことを言うことさえできます)。pytestモジュールをインストールしていませんでした。簡単な方法でapt install python-pytest修正しました。

「pytest」は、テストの依存関係としてsetup.pyにリストされていました。テスト要件もインストールしてください。


3

同様の問題がありました。 pytest私が働いていた環境にインストールされたモジュールを認識しませんでした。

pytest同じ環境にもインストールして解決しました。


私はvenv内からpytestを使用していましたが、グローバルにインストールしていて、このエラーが発生しました。グローバルバージョンをアンインストールしてvenv内にインストールした後、動作しました。
Markus Ressel

2

私にとっての問題はtests.pytestsディレクトリとともにDjangoによって生成されました。削除tests.pyすることで問題は解決しました。


2

相対インポートを誤って使用したため、このエラーが発生しました。OPの例では、test_app.pyは、たとえば、

from repo.app import *

ただし、自由に__init__.pyファイルがファイル構造の周りに散在している場合、これは機能せ、ファイルとテストファイルが同じディレクトリにない限り、見られるようなImportErrorが作成されます。

from app import *

これは、私のプロジェクトの1つで何をしなければならなかったかの例です。

これが私のプロジェクト構造です:

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

test_activity_indicator.pyからactivity_indicator.pyにアクセスできるようにするには、以下を行う必要があります。

  • 正しい相対インポートでtest_activity_indicatory.pyを開始します。
    from microbit.activity_indicator.activity_indicator import *
  • プロジェクト構造全体に__init__.pyファイルを配置します。
    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

モジュールをインポートできないことが原因でテストが中断されることがよくありました。調査の結果、システムが間違った場所でファイルを参照しており、モジュールを含むファイルをコピーすることで問題を簡単に解決できることがわかりました。適切にインポートするために、上記と同じフォルダ。もう1つの解決策は、インポートの宣言を変更し、MutPyにユニットの正しいパスを表示することです。ただし、複数のユニットがこの依存関係を持っている可能性があるという事実のため、宣言でも変更をコミットする必要があるため、ユニットをフォルダに移動するだけです。


OPの質問を提供する他の回答があり、それらはしばらく前に投稿されました。回答を投稿するときは、特に古い質問に回答する場合は、新しいソリューションを追加するか、大幅に優れた説明を追加してください。特定の回答についてコメントを投稿した方がよい場合もあります。
help-info.de

:ここで質問に答えるためのガイドへのリンクです:@ help-info.deからのコメントへの追加としてstackoverflow.com/help/how-to-answer
NODの手

0

Dirk AveryによるMediumの投稿によると(私の個人的な経験でサポートされています)、プロジェクトに仮想環境を使用している場合、システム全体のpytestのインストールは使用できません。仮想環境にインストールして、そのインストールを使用する必要があります。

特に、両方にインストールしている場合はpytest、システムインストールを使用するため、コマンドを実行するだけでは機能しません。他の答えが述べたように、1つの簡単な解決策はのpython -m pytest代わりに実行することですpytest。これは、環境のバージョンのpytestを使用しているため機能します。または、システムのバージョンのpytestをアンインストールすることもできます。仮想環境を再アクティブ化した後、pytestコマンドは機能するはずです。


これまでのところ私のために働いた唯一のものはでしたpython -m pytest tests/
Nik O'Lai

0

Flaskチュートリアルに従うと同じ問題が発生し、公式のPytestで答えが見つかりました ドキュメントで これは、私(および他の多くの人)が慣れている方法から少しずれています。

あなたが作成する必要があります setup.pyプロジェクトのルートディレクトリに、少なくとも次の2行ファイル必要があります。

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

PACKAGENAMEはアプリの名前です。次に、pipでインストールする必要があります。

pip install -e .

この-eフラグは、パッケージを編集可能モードまたは「開発」モードでインストールするようにpipに指示します。したがって、次に実行pytestしたときに、標準でアプリが見つかりますPYTHONPATH


0

私の解決策:

以下を含むディレクトリにconftest.pyファイルを作成しますtest

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

これにより、すべてのテストファイルを変更したり、env変数を設定したり、絶対/相対パスをいじったりすることなく、対象のフォルダーをpythonパスに追加します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.