Python
Pycharm
相対import
ExternalTools

相対importを使ったPythonファイルをPyCharmで実行する

相対importを使ったPythonファイルをPyCharm上で実行しようとして、うまく動かないって経験ありませんか?

TL;DR

Sources Rootを適切に設定したうえで、以下の設定でExternal Toolsを追加する。

  • Program: $ModuleSdkPath$
  • Parameters: -c "import os,runpy;runpy.run_module('.'.join(r'$FilePathRelativeToSourcepath$'.replace(os.sep,'.').split('.')[:-1]),{},__name__,1)"
  • Working directory: $ProjectFileDir$

うまく実行できない例

例えば、my_pkgという自作のパッケージ内で下のようなファイルを作ります。

my_pkg/foo.py
x = 42
my_pkg/bar.py
from .foo import x

if __name__ == '__main__':
    print(x)

ここで my_pkg/bar.py をPyCharmで開いて単純に Run すると以下のような例外が発生します。

/usr/bin/python3 /tmp/my_pkg/bar.py
Traceback (most recent call last):
  File "/tmp/my_pkg/bar.py", line 1, in <module>
    from .foo import x
ModuleNotFoundError: No module named '__main__.foo'; '__main__' is not a package

Process finished with exit code 1

原因

理由については、こちら の記事などで詳しく説明されています。
結論だけ言えば、-mオプションをつけて、モジュールの完全修飾名 (my_pkg.bar) を指定して実行するとうまく動きます。

# ERROR!!
/usr/bin/python3 /tmp/my_pkg/bar.py

# OK
cd /tmp
/usr/bin/python3 -m my_pkg.bar

つまり、どうにかしてPyCharmに-mオプション形式で実行させれば良いわけです。

解決策 1. 愚直に Edit Configuration settings する

下の画像のように設定すると-mオプション形式で実行させることができます。
しかしこの方法には、実行したいファイルごとに毎回この設定をしなければならない という極めて深刻な問題があります。

edit_configurations.png

edit_configurations2.png

解決策 2. External Tools を使う

PyCharm には、外部の実行ファイルを扱う機能が備わっているので、これを利用します。
少し面倒ですが、一度設定するだけで全てのプロジェクトで使えるようになるのが利点です。

External Tools の新規作成

メニューバーの File → Settings → Tools → External Tools と進んで新しい External Tools を追加してください。

external_tools.png

external_tools2.png

Tool settingsの部分は以下のように設定してください。

  • Program: $ModuleSdkPath$
  • Parameters: -c "import os,runpy;runpy.run_module('.'.join(r'$FilePathRelativeToSourcepath$'.replace(os.sep,'.').split('.')[:-1]),{},__name__,1)"
  • Working directory: $ProjectFileDir$

Sources Rootの設定

あとは my_pkg の親ディレクトリを右クリックして、Sources Rootとして登録すればOKです。

external_tools3.png

実行

bar.pyを開いた状態で、メニューバーの Tool → External Tools → python -m をクリックしてください。
きちんと実行できたら成功です。頻繁に使うようであれば、ショートカットキーを割り当てておくと便利です。