pythonでvenvを使ってみる

背景

以前から引き続きPythonの学習を進めています。

もともとRubyの方が知っている私にとって、bundlerでいうのようにプロジェクトごとに利用するモジュールをわける方法はなんだろう?という疑問が残っていました。

調べてみると以下のページが見つかります。

gem, bundler と pip, venv の比較

このページをみると、bundlerの–pathオプションにて設定する場合と同等のことがvenvを用いてできると書かれていました。

venvに俄然興味が出てきたので、venvについて調べたことを記していきたいと思います。

venvとは

公式サイトには以下のように記載されています。

1
2
3
4
venv モジュールは、軽量な "仮想環境" の作成のサポートを提供します。
仮想環境には、仮想環境ごとの site ディレクトリがあり、これはシステムの site ディレクトリから分離させることができます。
それぞれの仮想環境には、それ自身に (この仮想環境を作成するのに使ったバイナリのバージョンに合った) Python バイナリがあり、
仮想環境ごとの site ディレクトリに独立した Python パッケージ群をインストールできます。

ということなので、bundlerと同等の機能が提供されていそうです。早速インストールしてみます。

venvのインストール

venvのインストール方法は

1
python -m venv /path/to/new/virtual/environment

と書かれています。Djangoのプロジェクト配下にvenvというディレクトリを作成してそこで管理しようと考えていたので、インストールコマンドは以下のようになります。

1
2
$ cd django_project
$ python -m venv venv

実行すると、djangoプロジェクトの配下にvenvというディレクトリが作成されました。

venvディレクトリ配下のファイルを確認します

1
2
$ ls venv
bin include lib pyvenv.cfg

各ファイル、ディレクトリの役割を見ていきます

binディレクトリ

binディレクトリの中のファイルを確認します

1
2
3
4
5
6
7
8
9
10
11
12
$ ls venv/bin
total 72
-rw-r--r-- 1 user staff 8834 7 19 21:34 Activate.ps1
-rw-r--r-- 1 user staff 1909 7 19 21:34 activate
-rw-r--r-- 1 user staff 858 7 19 21:34 activate.csh
-rw-r--r-- 1 user staff 1998 7 19 21:34 activate.fish
-rwxr-xr-x 1 user staff 250 7 19 21:34 pip
-rwxr-xr-x 1 user staff 250 7 19 21:34 pip3
-rwxr-xr-x 1 user staff 250 7 19 21:34 pip3.9
lrwxr-xr-x 1 user staff 60 7 19 21:33 python -> /Users/user/.anyenv/envs/pyenv/versions/3.9.5/bin/python
lrwxr-xr-x 1 user staff 6 7 19 21:33 python3 -> python
lrwxr-xr-x 1 user staff 6 7 19 21:33 python3.9 -> python

venvを有効にするactivateスクリプトと、python、pipがあります。pythonはこのプロジェクトで利用しているpyenvのpythonへのリンクになっています。

includeディレクトリ

includeディレクトリは空でした。有効化した後に変化が起こるか見て見たいと思います。

lib

libディレクトリはこの仮想環境でモジュールがインストールされるディレクトリです。

1
2
3
4
5
6
7
8
9
$ ls -l venv/lib/python3.9/site-packages/
total 8
drwxr-xr-x 5 user staff 160 7 19 21:33 _distutils_hack
-rw-r--r-- 1 user staff 152 7 19 21:33 distutils-precedence.pth
drwxr-xr-x 8 user staff 256 7 19 21:33 pip
drwxr-xr-x 10 user staff 320 7 19 21:34 pip-21.1.1.dist-info
drwxr-xr-x 7 user staff 224 7 19 21:33 pkg_resources
drwxr-xr-x 41 user staff 1312 7 19 21:33 setuptools
drwxr-xr-x 11 user staff 352 7 19 21:33 setuptools-56.0.0.dist-info

pipなど標準でインストールされているモジュールが表示されていることがわかります。

pyvenv.cfg

1
2
3
home = /Users/user/.anyenv/envs/pyenv/versions/3.9.5/bin
include-system-site-packages = false
version = 3.9.5

pythonのディレクトリや、バージョンなどが記載されています。

venvの有効化

作成した仮想環境を有効にするにはbinディレクトリの下にあったactivateスクリプトを読み込みます。

1
2
$ source venv/bin/activate
(venv) $

プロンプトの先頭に(venv)が追加されました。仮想環境が有効になっていることがわかります。

無効にする場合はdeactivateコマンドを実行します。

1
2
(venv) $ deactivate
$

プロンプトの(venv)がなくなりました。

仮想環境へのパッケージのインストール

次にパッケージのインストールを行ってみます。

試しに仮想環境でないグローバルなpython3.9.5のインストール済パッケージ一覧を出力します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ pip list
Package Version
--------------- --------
awscli 1.18.169
botocore 1.19.9
colorama 0.4.3
docutils 0.15.2
jmespath 0.10.0
pip 21.1.1
pyasn1 0.4.8
python-dateutil 2.8.1
PyYAML 5.3.1
rsa 4.5
s3transfer 0.3.3
setuptools 56.0.0
six 1.15.0
urllib3 1.25.11
WARNING: You are using pip version 21.1.1; however, version 21.1.3 is available.
You should consider upgrading via the '/Users/user/.anyenv/envs/pyenv/versions/3.9.5/bin/python3.9 -m pip install --upgrade pip' command.

pipのバージョンが最新ではないという警告が出ていますが一旦置いておいて、わたしのグローバルな環境のパッケージの一覧を出してみました。

次に仮想環境を有効にしたあと、パッケージ一覧を出力してみます。

1
2
3
4
5
6
7
8
$ source venv/bin/activate
(venv) $ pip list
Package Version
---------- -------
pip 21.1.1
setuptools 56.0.0
WARNING: You are using pip version 21.1.1; however, version 21.1.3 is available.
You should consider upgrading via the '/Users/user/github/django/venv/bin/python -m pip install --upgrade pip' command.

同じ警告は出ていますが、インストール済パッケージの数が違います。

では、警告に出ているコマンドを実行して仮想環境のpipのバージョンを更新してみましょう。

1
2
3
4
5
6
7
8
9
10
(venv) $ python -m pip install --upgrade pip
Requirement already satisfied: pip in ./venv/lib/python3.9/site-packages (21.1.1)
Collecting pip
Using cached pip-21.1.3-py3-none-any.whl (1.5 MB)
Installing collected packages: pip
Attempting uninstall: pip
Found existing installation: pip 21.1.1
Uninstalling pip-21.1.1:
Successfully uninstalled pip-21.1.1
Successfully installed pip-21.1.3

pip-21.1.3をインストールしました。警告が出なくなっていることを確認しましょう。

1
2
3
4
5
(venv) $ pip list
Package Version
---------- -------
pip 21.1.3
setuptools 56.0.0

グローバル環境の確認

ここで一旦仮想環境を止めてみます。

1
2
(venv) $ deactivate
$

pip listでインストール済パッケージ一覧を確認します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ pip list
Package Version
--------------- --------
awscli 1.18.169
botocore 1.19.9
colorama 0.4.3
docutils 0.15.2
jmespath 0.10.0
pip 21.1.1
pyasn1 0.4.8
python-dateutil 2.8.1
PyYAML 5.3.1
rsa 4.5
s3transfer 0.3.3
setuptools 56.0.0
six 1.15.0
urllib3 1.25.11
WARNING: You are using pip version 21.1.1; however, version 21.1.3 is available.
You should consider upgrading via the '/Users/user/.anyenv/envs/pyenv/versions/3.9.5/bin/python3.9 -m pip install --upgrade pip' command.

グローバル環境はあいかわらず警告が出ています。先ほどpipをアップグレードしたのは仮想環境のみとなります。

仮想環境を有効にしてパッケージをインストールすれば仮想環境にのみインストールされるということがわかりました。

仮想環境の削除

仮想環境を削除するには作成した仮想環境のディレクトリ(今回はvenv)を削除すれば良さそうです。

1
$ rm -rf venv

git管理について

ここで一つ疑問に思ったのは、Gemfile、Gemfile.lockのようにgit管理にして、誰でも同じような環境を構築できるようにするにはどうしたらよいのか?ということです。

pyvenv.cfgにはpythonへのパスがフルパスで記載されているので、各利用者によって異なってしまいます。ですので、git管理には向いていなさそうです。

インストール済パッケージもファイル数としては膨大なのでgit管理には向いていません。

できることは、RubyでいうGemfile.lockを作ってそれをgit管理することでしょうか。

requirements.txtを作成する

RubyでいうGemfile.lockはrequirements.txtというファイルです。

requirements.txtを作成するにはpip freezeコマンドを利用します。

https://pip.pypa.io/en/stable/cli/pip_freeze/

では実際に仮想環境で作成してみます。

1
2
3
$ source venv/bin/activate
(venv) $ pip freeze
(venv) $

ん?なにも出力されません…と思ったら特に何もモジュールをインストールしていないからなにも出力されないのでした…

試しにDjangoをインストールしてみます。現時点で最新の3.2.5をインストールしてみます。

1
2
3
4
5
6
7
8
9
10
11
(venv) $ pip install django==3.2.5
Collecting django==3.2.5
Using cached Django-3.2.5-py3-none-any.whl (7.9 MB)
Collecting asgiref<4,>=3.3.2
Using cached asgiref-3.4.1-py3-none-any.whl (25 kB)
Collecting sqlparse>=0.2.2
Using cached sqlparse-0.4.1-py3-none-any.whl (42 kB)
Collecting pytz
Using cached pytz-2021.1-py2.py3-none-any.whl (510 kB)
Installing collected packages: sqlparse, pytz, asgiref, django
Successfully installed asgiref-3.4.1 django-3.2.5 pytz-2021.1 sqlparse-0.4.1

インストールできました。この状態でpip freezeを実行してみます。

1
2
3
4
5
$ pip freeze
asgiref==3.4.1
Django==3.2.5
pytz==2021.1
sqlparse==0.4.1

この出力をrequirements.txtとして保存してgit管理するのがよいかと思います。

まとめ

Rubyとの違いに戸惑いながらなんとかPythonを学んでいっています。今回のvenvについては、Dockerを利用している場合はあまり関係ありません。Docker内のPythonにインストールされるためです。

ですが、Pythonのパッケージを追加するたびにイメージのビルドをしないといけないとするとそれはとても面倒ですね…Dockerでvenvを使ってそのディレクトリをDocker Volumeとしていくのが良いのでしょうか。

次回はこのあたりを考えていきたいと思います。