LoginSignup
3
7

More than 3 years have passed since last update.

Pythonでdirenvを使う。上位ディレクトリからimportする方法

Last updated at Posted at 2020-09-24

この記事で解決したい問題

今まで適当に配置していたpythonファイルたち、プロジェクトが大きくなってフォルダ整理することにしました。ここで発生したのが自作ライブラリをインポートできない問題です。pythonでは実行フォルダおよびその配下のフォルダだけがモジュール検索対象のパスとなっているので、自分より上位にあるファイルからインポートができません。

今まではsys.path.appendを使って上位にあるファイルからインポートしていましたが、以下のようなデメリットがあり、sys.path.append を使わずに解決する方法はないものかと悩んでいました。

sys.path.append の弱点

sys.path.appendを使って上位ファイルからインポートをしようとすると、ファイルの最初の数行が必ず次のようになります。

import sys
import pathlib

sys.path.append(str(pathlib.Path(__file__).resolve().parents[1]))
from MyModule.MyClass import MyClass

これの何が嫌かと言うと、

  • 上位ファイルからインポートしたい全部のファイルでsys.path.appendしなければならない
  • autopep8などコードの自動整形ツールを使うとimportの文が勝手に上に移動されてしまう

という点です。きれいなコードを書きたいという理想にどうしても相反してしまいますよね。

そんな悩みを今回解決してくれるのが direnv です。direnv はディレクトリ毎に .envrc に環境変数を定義することで、.envrcがあるディレクトリがカレントディレクトリになった時だけ環境変数を有効にしてくれるツールです。

筆者の開発環境

OS:macOS Catalina 10.15.6
brew 2.5.2
bash : 3.2.57(1)-release (x86_64-apple-darwin19)
Python : 3.6.10

今回の説明で用いるフォルダ構造

grand_mother
┣ mother
┃ ┗ me.py
┗ aunt
  ┗ cousin.py 

me.pycousin.pyをインポートして使うことを想定して説明します。
me.pycousin.pyはそれぞれ以下のようになっています。

cousin.py
class Cousin:
    name = 'Reon'
    age = 14
me.py
from aunt.cousin import Cousin
print('name :', Cousin.name)
print('age :', Cousin.age)

direnvをインストールする

Macの場合はbrewコマンド一発です。

$ brew install direnv

Macでない場合はgit cloneします。

$ cd /path/to/directory # インストールしたい場所
$ git clone https://github.com/direnv/direnv
$ cd direnv
$ sudo make install

bashにhookを追加します。

~/.bashrc
eval "$(direnv hook bash)"

~/.bashrcの再読み込みしてdirenvを動作するようにします。

$ source ~/.bashrc

direnvを使えるようにする

環境変数を設定するプロジェクトのトップ(今回であれば grand_mother/ )に移動して、以下のコマンドを実行します。

$ cd 〇〇/grand_mother
$ direnv edit .

すると grand_mother/.envrc が作成されるので PYTHONPATH を追加します。

grand_mother/.envrc
export PYTHONPATH="〇〇/grand_mother:$PYTHONPATH"

これで grand_mother 内のファイルで from mother importfrom aunt import などができるようになります。

PYTHONPATH とは

PYTHONPATHはpythonがモジュールを読み込む時にデフォルトのpythonモジュールに加えてモジュールを探しに行くディレクトリを追加するものです。以下のコマンドで今設定されているPYTHONPATHを確認できます。

# PYTHONPATHを確認
$ echo $PYTHONPATH

# PYTHONを含む環境変数を全て表示
$ printenv | grep PYTHON

また、pythonがモジュールを読み込む時に読み込むディレクトリを全て見たいのであればpythonのsys.pathで確認できます。

import sys
print(sys.path)

(必要な人のみ) .envに環境変数を書きたい場合

この記事を参考にして、grand_mother/.env の方に環境変数を書く場合も説明します。自分もすでに他の環境変数を .env に書いていたので、この方式を採用しました。

.envrcはこれだけです。

grand_mother/.envrc
dotenv

.envの方に以下の一文を追加しましょう。

grand_mother/.env
PYTHONPATH=/〇〇/grand_mother/

direnvの動作を確認する

.envrc を設定したら

direnv: error .envrc is blocked. Run `direnv allow` to approve its content.

こんなエラー文が表示されているかもしれません。その時はエラー文にある通り、direnv allowを実行して、PYTHONPATHが追加されたことを確認します。.envrcを書き換えるたびにこの文章は表示されます。

$ direnv allow
direnv: loading ~/〇〇/grand_mother/.envrc
direnv: export +PYTHONPATH

.envrcがあるディレクトリから抜けると、direnvが一時無効化されます。

$ cd ..
direnv: unloading

再度、.envrcがあるディレクトリに入ると.envrcの内容が環境変数に追加されていることがわかります。

$ cd grand_mother/
direnv: loading .envrc

解決しました

これで me.py を実行するとうまくいきます。

$ python mother/me.py
name : Reon
age : 14

.envrcの運用

GitHubなどでソースコードを共有する場合、 .env や .envrc には盗まれると困る情報が乗っている。あるいは実行環境によって異なる値を設定すべき場合があるので、.gitignoreに.envrcを追加するなどして、リポジトリにコミットしないようにしましょう。

(補足) Amazon Linux にもdirenvを導入する

今回自分のローカルに合わせて、運用していたAmazon Linuxの方にもdirenvを入れる必要があったので、そのときの作業内容も書いておきます。

Amazon Linuxの環境

$ cat /etc/os-release
Amazon Linux AMI 2018.03
$ bash --version
GNU bash, バージョン 4.2.46(2)-release (x86_64-redhat-linux-gnu)

まず、Amazon Linux にはdirenvを動かすためのgoが入ってないのでインストールする必要があります。

$ sudo yum install golang -y

そして、この記事の上の方にあるように、git cloneしてdirenvをインストールします。

$ cd /path/to/directory # インストールしたい場所
$ git clone https://github.com/direnv/direnv
$ cd direnv
$ sudo make install

bashにGOPATHとdirenvのhookを追加します。GOPATHは、ビルドをするための場所の指定なので、任意の場所で大丈夫です。

~/.bashrc
export GOPATH=$HOME/go

eval "$(direnv hook bash)"

~/.bashrcの再読み込みして、設定結果を確認しておきましょう。

$ source ~/.bashrc
$ echo $GOPATH
/home/ec2-user/go

あとは、記事の上の方に書いた direnvを使えるようにする のやり方で Amazon Linux でもdirenvが使えるようになりました。

参考記事

3
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
7