web-dev-qa-db-ja.com

Python検索パスを他のソースに展開

私は、かなり大きな既存のコードベースでプロジェクトに参加しました。 Linuxで開発し、IDEは使用しません。コマンドラインを実行します。プロジェクトモジュールを実行するときにpythonを取得して正しいパスを検索する方法を見つけようとしています。たとえば、次のようなものを実行すると:

python someprojectfile.py

私は得る

ImportError: no module named core.'somemodule'

私はすべてのインポートでこれを取得しますが、パスの問題だと思います。

TLDR:

インポートステートメント中にPythonを取得して~/codez/project/およびすべてのファイルとフォルダーで* .pyファイルを検索するにはどうすればよいですか。

81
themaestro

これを行うには、いくつかの可能な方法があります。

  • 環境変数PYTHONPATHをディレクトリのコロン区切りリストに設定して、インポートされたモジュールを検索します。
  • プログラムで、sys.path.append('/path/to/search')を使用して、インポートしたモジュールを検索するPythonに必要なディレクトリの名前を追加します。 sys.path は、ディレクトリのリストですPythonは、モジュールのインポートを求められるたびに検索し、必要に応じて変更できます(ただし、標準ディレクトリ!)。環境変数PYTHONPATHに配置したディレクトリは、Pythonの起動時にsys.pathに挿入されます。
  • site.addsitedir を使用して、ディレクトリをsys.pathに追加します。これと単純な追加の違いは、addsitedirを使用すると、そのディレクトリ内で.pthファイルも検索し、それらを使用して、ファイルの内容に基づいてsys.pathに追加のディレクトリを追加することです。詳細については、ドキュメントを参照してください。

どちらを使用するかは、状況によって異なります。プロジェクトを他のユーザーに配布する場合、通常、PythonコードファイルがPythonのインポーターによって自動的に検出されるようにプロジェクトをインストールします(つまり、パッケージは通常site-packagesディレクトリにインストールされます)コード内でsys.pathを台無しにした場合、それは不要である可能性があり、そのコードが別のコンピューターで実行されると悪影響を与える可能性さえあります。開発のために、PYTHONPATHを設定するのが通常最善の方法であると推測します。

ただし、自分のコンピューターで実行するだけの何かを使用している場合(または、Webアプリのフレームワークなどで非標準のセットアップを使用している場合)、次のようなことを行うことは珍しくありません。

import sys
from os.path import dirname
sys.path.append(dirname(__file__))
143
David Z

また、次のpythonパッケージについて読む必要があります。 http://docs.python.org/tutorial/modules.html

あなたの例から、あなたは本当に~/codez/projectにパッケージがあると思います。 pythonディレクトリの__init__.pyファイルは、ディレクトリをネームスペースにマップします。すべてのサブディレクトリに__init__.pyファイルがある場合、ベースディレクトリをPYTHONPATHに追加するだけです。例えば:

PYTHONPATH = $ PYTHONPATH:$ HOME/adaifotis/project

Davidが説明するように、PYTHONPATH環境変数をテストすることに加えて、次のようにpythonでテストできます。

$ python
>>> import project                      # should work if PYTHONPATH set
>>> import sys
>>> for line in sys.path: print line    # print current python path

...

11
Andrew B.

私はこのスレッドが少し古いことを知っていますが、これの中心に到達するのに時間がかかりましたので、共有したいと思いました。

私のプロジェクトでは、親ディレクトリにメインスクリプトがあり、モジュールを区別するために、すべてのサポートモジュールを「モジュール」と呼ばれるサブフォルダーに入れました。メインスクリプトで、これらのモジュールを次のようにインポートします(report.pyというモジュールの場合)。

from modules.report import report, reportError

メインスクリプトを呼び出すと、これが機能します。ただし、各モジュールにmain()を含めて、各モジュールをテストし、それぞれを直接呼び出したいと思いました。

python modules/report.py

Pythonは、「モジュールと呼ばれるモジュール」が見つからないと文句を言います。ここで重要なのは、デフォルトで、Pythonは検索パスにスクリプトのフォルダーを含むことですが、CWDではありません。したがって、このエラーが実際に言うのは、「モジュールのサブフォルダーが見つかりません」です。これは、report.pyモジュールが存在するディレクトリに「モジュール」サブディレクトリがないためです。

これに最も近い解決策は、Python検索パスにCWDを追加することで、これを最上部に含めることです。

import sys

sys.path.append(".")

これでPythonがCWD(現在のディレクトリ)を検索し、「モジュール」サブフォルダーを見つけました。すべてうまくいきました。

4
Tom Gordon

私が見つける最も簡単な方法は、ファイル「any_name.pth」を作成し、それをフォルダー「\ Lib\site-packages」に入れることです。このフォルダーは、pythonがインストールされている場所にあります。

そのファイルに、インポート用のモジュールを保持するディレクトリのリストを配置します。たとえば、このファイルに次のような行を作成します。

C:\ Users\example ...\example

Pythonでこれを実行することで動作することを確認できます:

import sys
for line in sys: print line

インポートできるディレクトリをはじめ、ディレクトリが印刷されます。これで、そのディレクトリにある「mymodule.py」ファイルを次のように簡単にインポートできます。

import mymodule

これはサブフォルダーをインポートしません。そのために、pythonスクリプトを作成して、定義したフォルダーのすべてのサブフォルダーを含む.pthファイルを作成することを想像できます。おそらく起動時に実行してください。

3
KieranPC

私はこの質問を読んで答えを探しましたが、どれも好きではありませんでした。

だから私は迅速で汚い解決策を書いた。これをsys.pathのどこかに置くだけで、folder(現在の作業ディレクトリから)またはabspathの下にディレクトリが追加されます。

#using.py

import sys, os.path

def all_from(folder='', abspath=None):
    """add all dirs under `folder` to sys.path if any .py files are found.
    Use an abspath if you'd rather do it that way.

    Uses the current working directory as the location of using.py. 
    Keep in mind that os.walk goes *all the way* down the directory tree.
    With that, try not to use this on something too close to '/'

    """
    add = set(sys.path)
    if abspath is None:
        cwd = os.path.abspath(os.path.curdir)
        abspath = os.path.join(cwd, folder)
    for root, dirs, files in os.walk(abspath):
        for f in files:
            if f[-3:] in '.py':
                add.add(root)
                break
    for i in add: sys.path.append(i)

>>> import using, sys, pprint
>>> using.all_from('py') #if in ~, /home/user/py/
>>> pprint.pprint(sys.path)
[
#that was easy
]

そして、私はいくつかのランダムなツール用のフォルダーを持ち、それらをパッケージまたは何かの一部にせずに、数行のコードでそれらの一部(またはすべて)にアクセスできるので、それが好きです。

2
Droogans

古い質問の新しいオプション
Debianにfail2banパッケージをインストールすると、/usr/lib/python3/dist-packages/fail2banにインストールするのはpython3 sys.pathにないパスにハードコードされているようです。


> python3
Python 3.7.3 (v3.7.3:ef4ec6ed12, Jun 25 2019, 18:51:50)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python37.Zip', '/usr/lib/python3.7', '/usr/lib/python3.7/lib-dynload', '/usr/lib/python3.7/site-packages']
>>>

そのため、単にコピーするのではなく、ライブラリを新しいバージョンにリンク(bash)しました。
元のアプリの今後の更新は、リンクされたバージョンにも自動的に適用されます。

 if [ -d /usr/lib/python3/dist-packages/fail2ban ]
   then
      for d in /usr/lib/python3.*
      do
         [ -d ${d}/fail2ban ] || \
            ln -vs /usr/lib/python3/dist-packages/fail2ban ${d}/
      done
   fi
0
fcm