プロジェクトで決められた親ディレクトリ(相対パス)からパッケージのimportを行ったところ、ModuleNotFoundErrorが出てしまい、importができずに困ったので、その際の対応方法についてメモ書きします。
事象説明
次の画像のように、backend
ディレクトリを親とした状態で、data_file.py
、common_file.py
モジュールを読み込みjob_exec.py
を実行したいとします。
data_file.py
とcommon_file.py
の内容は次のようになっています。
# data_file.py
HOGE_DATA = 'hoge_data'
# common_file.py
HOGE_NAME = 'hoge_hoge'
この状態でjob_exec.py
を実行すると、モジュールの読み込みに失敗します。
プロジェクトとしてはbackend
を起点(親)として、上記のようなimportをしています。
しかし、私だけ読み込めない。「なんでや!!」となり困った訳です。
解決策
結論としては、sys.path.append("親ディレクトリ")
と設定すれば、読み込めるようになります。
sys.pathには、標準ライブラリやインストールしたパッケージ、自作パッケージなどを探索するパスが設定されています。参考
sys.path.append("親ディレクトリ")
を実行することで、sys.pathに親ディレクトリを設定できる訳です。
一番最初に実行するモジュールに次のような処理を記述することで、モジュールを読み込んでくれるようになります。
from os.path import dirname, abspath
import sys
# job_exex.pyから3つ上のディレクトリの絶対パスを取得し、sys.pathに登録する
parent_dir = dirname(dirname(dirname(abspath(__file__)))) # 追加
if parent_dir not in sys.path: # 追加
sys.path.append(parent_dir) # 追加
from data.data_file import HOGE_DATA
from src.common.common_file import HOGE_NAME
print(HOGE_DATA)
print(HOGE_NAME)
hoge_data
hoge_hoge
sys.pathの内容確認
次のようにコードを書いて実行すると、sys.pathの内容を確認できます。
import sys
import pprint
pprint.pprint(sys.path)
['/Users/username/python_path/backend/src/job',
'/Users/username/.pyenv/versions/3.8.6/lib/python38.zip',
'/Users/username/.pyenv/versions/3.8.6/lib/python3.8',
'/Users/username/.pyenv/versions/3.8.6/lib/python3.8/lib-dynload',
'/Users/username/.pyenv/versions/3.8.6/lib/python3.8/site-packages']
sys.path.append(parent_dir)
を実行すると、sys.pathに設定が追加されていることを確認できます。
from os.path import dirname, abspath
import sys
import pprint
parent_dir = dirname(dirname(dirname(abspath(__file__)))) # 追加
sys.path.append(parent_dir) # 追加
pprint.pprint(sys.path)
['/Users/username/python_path/backend/src/job',
'/Users/username/.pyenv/versions/3.8.6/lib/python38.zip',
'/Users/username/.pyenv/versions/3.8.6/lib/python3.8',
'/Users/username/.pyenv/versions/3.8.6/lib/python3.8/lib-dynload',
'/Users/username/.pyenv/versions/3.8.6/lib/python3.8/site-packages',
'/Users/username/python_path/backend']