web-dev-qa-db-ja.com

pytestで正しくインポートする

私はpytestをPython 2.6。私のプログラムと同じ方法です。

私のディレクトリ構造は次のとおりです。

src/
    main.py
    util.py
    test/
        test_util.py
    geom/
        vector.py
        region.py
        test/
            test_vector.py
            test_region.py

実行するには、src /からpython main.pyを呼び出します。

Main.pyで、ベクターとリージョンの両方をインポートします

from geom.region import Region
from geom.vector import Vector

Vector.pyで、リージョンをインポートします

from geom.region import Region

標準実行でコードを実行すると、これらはすべて正常に機能します。ただし、src /から「py.test」を呼び出すと、インポートエラーで常に終了します。


いくつかの問題と解決策の試み

私の最初の問題は、「test/test_foo.py」を実行するときに、py.testが「foo.pyを直接インポートできない」ということでした。 「imp」ツールを使用してこれを解決しました。 「test_util.py」内:

import imp
util = imp.load_source("util", "util.py")

これは多くのファイルに最適です。また、pytestが「path/foo/py」をテストするために「path/test/test_foo.py」を実行している場合、それはディレクトリ「path」に基づいていることを暗示しているようです。

ただし、「test_vector.py」ではこれは失敗します。 Pytestはvectorモジュールを見つけてインポートできますが、cannotvectorのインポートのいずれかを見つけます。 pytestを使用すると、( "vector.py"からの)次のインポートは両方とも失敗します。

from geom.region import *
from region import *

これらは両方ともフォームのエラーを与えます

ImportError: No module named [geom.region / region]

この問題を解決するために次に何をすべきかわかりません。 Pythonでのインポートの私の理解は限られています。

pytestを使用するときにインポートを処理する適切な方法は何ですか?


編集:非常にハッキングされたソリューション

vector.pyで、インポートステートメントを

from geom.region import Region

単純に

from region import Region

これにより、インポートは「vector.py」のディレクトリに対して相対的になります。

次に、「test/test_vector.py」で、「vector.py」のディレクトリを次のようにパスに追加します。

import sys, os
sys.path.append(os.path.realpath(os.path.dirname(__file__)+"/.."))

これにより、Python= "geom/test/test_vector.py"から "../region.py"を見つけることができます。

これは機能しますが、大量の新しいディレクトリをパスに追加しているため、非常に問題が多いようです。私が探しているのは

1)pytestと互換性のあるインポート戦略、または

2)インポート戦略と互換性のあるpytestのオプション

ですから、私はこの種の答えのためにこの質問を開いたままにします。

31
NcAdams

importは、次のディレクトリを検索してモジュールを見つけます。

  1. プログラムのホームディレクトリ。これは、ルートスクリプトのディレクトリです。 pytestを実行している場合、ホームディレクトリはインストール先(おそらく/ usr/local/bin)にあります。 pytestの場所によってホームディレクトリが決まるため、srcディレクトリから実行していても関係ありません。それがモジュールを見つけられない理由です。
  2. [〜#〜] pythonpath [〜#〜]。これは環境変数です。オペレーティングシステムのコマンドラインから設定できます。 Linux/Unixシステムでは、次を実行することでこれを行うことができます: 'export PYTHONPATH =/your/custom/path'必要な場合Pythonテストディレクトリからモジュールを見つけるには、この変数にsrcパスを含める必要があります。
  3. 標準ライブラリディレクトリ。これは、すべてのライブラリがインストールされるディレクトリです。
  4. pthファイルを使用するあまり一般的ではないオプションがあります。

sys.pathは、home directory[〜 #〜] pythonpath [〜#〜]および標準ライブラリディレクトリ。あなたがしていることは、sys.pathの修正が正しいことです。それは私が定期的に行うことです。 [=#〜] pythonpath [〜#〜]を使用してみてくださいsys.path

14
Jose Varez

ここでの問題は、Pytestがファイルシステムを調べてテストを含むファイルを検出するが、importがそのファイルをロードするようにするモジュール名を生成する必要があることです。 (覚えておいてください ファイルはモジュールではありません 。)

Pytestは、これを思い付きます テストパッケージ名__init__.pyファイルを含まないファイルレベル以上の最初のディレクトリを見つけ、生成されたモジュールを含むモジュールツリーの「basedir」を宣言することによりこのファイルから。その後、basedirをsys.pathに追加し、basedirに関連するそのファイルを見つけるモジュール名を使用してインポートします。

これにはいくつか注意すべき点があります。

  1. ベースパスが意図したベースパスと一致しない場合があります。その場合、モジュールの名前は通常使用するものと一致しません。たとえば、geom.test.test_vectortest_vectorが見つからず、そのディレクトリを__init__.pyに追加したため、Pytestの実行中にsrc/geom/test/と考える名前は実際には単にsys.pathという名前になります。

  2. 異なるディレクトリにある2つのファイルの名前が同じ場合、モジュールの名前の衝突が発生する可能性があります。たとえば、__init__.pyファイルがどこにもない場合、geom/test/test_util.pyを追加すると、test/test_util.pyと競合します。両方ともimport test_util.pyとしてロードされ、パスにtest/geom/test/の両方が含まれます。

ここで使用しているシステムは、明示的な__init__.pyモジュールなしで、ディレクトリに対してPython create implicit namespace packages を持っています。パッケージはサブモジュールを持つモジュールです。)理想的には、Pytestでこれを生成するパスを設定するのが理想的ですが、その方法はわからないようです。

ここで最も簡単な解決策は、空の__init__.pyファイルをsrc/の下のすべてのサブディレクトリに追加することです。これにより、Pytestはsrc/の下のディレクトリ名で始まるパッケージ/モジュール名を使用してすべてをインポートします。

質問 PEP 420名前空間パッケージを使用してプロジェクトをPytestする方法 では、これに対する他のソリューションについて説明しています。

11
Curt J. Sampson

私もこの問題について何をすべきか疑問に思っていました。この投稿を読んで、少し遊んだ後、私はエレガントな解決策を見つけました。 「test_setup.py」というファイルを作成し、次のコードをその中に配置しました。

import sys, os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

このファイルを最上位ディレクトリ(srcなど)に配置します。 pytestを最上位ディレクトリから実行すると、ファイルの先頭に「test」が付いているため、これを含むすべてのテストファイルが実行されます。ファイルにはテストはありませんが、「test」で始まるため、実行されたままです。

コードは、test_setup.pyファイルの現在のディレクトリ名をテスト環境内のシステムパスに追加します。これは一度だけ行われるため、パスに追加されるものはありません。

次に、任意のテスト関数内から、その最上位フォルダーに関連するモジュールをインポートできます(import geom.region)そして、srcディレクトリがパスに追加されたので、それがどこにあるかを知っています。

すべてのファイルではなく、単一のテストファイル(test_util.pyなど)を実行する場合は、次を使用します。

pytest test_setup.py test\test_util.py

これにより、test_setupとtest_utilの両方のコードが実行されるため、test_setupコードを引き続き使用できます。

6
Joe Dimig