Python2.7: sys.pathで上位ディレクトリのモジュールを読み込む (Pythonスクリプト側の設定 + pylinterの設定)
モチベーション
次のようなディレクトリ構造で、group1/g1_main.pyの中、すなわちサブディレクトリから、上位ディレクトリにあるconfig.pyやutils.pyの中の関数や変数を読みたいことがあります。*1
./proj_root ├── __init__.py ├── config.py ├── group1 │ ├── __init__.py │ ├── g1_main.py │ └── g1_sub.py └── utils.py
通常は、エントリポイント(pythonコマンドで実行引数になるpythonスクリプト)が最上位ディレクトリにある場合は、 普通に from ..config import Config
というような相対インポートを書けばよいのですが、 エントリポイントがサブディレクトリにある場合はこの方法が使えません。
解決方法
そこで、PEP8違反ではありますが、次のような形式でsys.pathに親ディレクトリ(./proj_root)を追加することでサブディレクトリをエントリポイントとするPythonスクリプトを作成することが出来ます。
import os # noqa import sys # noqa sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # noqa
ただし、この方法でsys.pathをいじってもpylinterには反映されず、VSCode上でプログラムを書いていると警告が消えません。 そこで、pylinterの設定ファイルでカバーしてあげます。 pylinterの設定ファイルは、ざっくり次のような順番で読み込まれることがドキュメントで示されています。
Running Pylint — Pylint 2.2.1 documentation
この仕組みを用いて、プロジェクトのルートディレクトリに.pylintrcを追加し、次のようなinit-hook(初期化時に実行されるpythonスクリプト)を記述します。
この記事で示している.pylintrcはpylint.config.PYLINTRCを取得して、pylintrcが設置されているディレクトリのパスを取得し、取得したパスをsys.pathに追加します。 これによって、プロジェクトのルートディレクトリがpylint内でもsys.pathに登録された状態になるので、pylintによる間違った警告を抑制することができます。
./proj_root ├── __init__.py ├── config.py ├── .pylintrc ├── group1 │ ├── __init__.py │ ├── g1_main.py │ └── g1_sub.py └── utils.py
[MASTER] init-hook="import os, sys, pylint; sys.path.append(pylint.config.PYLINTRC)"
Reference
Running Pylint — Pylint 2.2.1 documentation
python - PyLint "Unable to import" error - how to set PYTHONPATH? - Stack Overflow