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

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

Python 2.6 で pytest を使用するようにセットアップしました。これまでのところ、「import」ステートメントの処理を除いてうまく動作しています。私のプログラムと同じように pytest をインポートに応答させることができないようです。

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

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

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

main.pyでは、vectorとregionの両方をインポートします。

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

vector.pyでは、regionをインポートして

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が、できないのインポートのいずれかを見つけますvector。次のインポート (「vector.py」から) は、pytest を使用すると両方とも失敗します。

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のオプション

したがって、私はこの質問をこの種の答えのために開いたままにしておきます。

ベストアンサー1

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

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

これには注意すべきいくつかの意味合いがあります:

  1. ベースパスが意図したベースパスと一致しない場合があります。その場合、モジュールの名前は通常使用する名前と一致しません。たとえば、 と考えているものは、実際にはPytest の実行中にgeom.test.test_vectorのみ名前が付けられます。に何も見つからず、そのディレクトリが に追加されたためです。test_vector__init__.pysrc/geom/test/sys.path

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

ここで使用しているシステムは、明示的な__init__.pyモジュールを使用せずにPythonで作成します暗黙の名前空間パッケージディレクトリ用です。(パッケージはサブモジュールを含むモジュールです。) 理想的には、これも生成するパスを使用して Pytest を構成するのですが、その方法がわからないようです。

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

質問PEP 420 名前空間パッケージを使用してプロジェクトを Pytest するにはどうすればよいですか?これに対する他の解決策について説明します。

おすすめ記事