Mac の python 環境について
Python on Mac な環境をちゃんと作る
Mac の Python 環境をテキトーに作ってたら、めんどうなことになってしまったので、この際きちんとやり直しながら勉強したいと思う。
発生した問題
普段 CLI で何か作業をすることが多く、そのときにタブをたくさん開かなくてもいいように tmux を使っている。
なのだが、ある時から急に powerline
が効かなくなった。
(これにより、Python 環境に問題があることに気がついた)
気軽な気持ちでこれを直そうとした結果、めんどくさい問題が発生していることが発覚する。
ちなみに、tmux の powerline
の読み込みは以下のようにしている
# .tmux.conf (関係する部分以外は略)
# tmux powerline (minimum)
run-shell "powerline-config tmux setup"
まず、この powerline-config
がきちんと使えているかチェックしたい。
sudachi@DaiMac:~ $ powerline-config
-bash: /usr/local/bin/powerline-config: /usr/local/opt/python@3.9/bin/python3.9: bad interpreter: No such file or directory
ないらしい。しかし、私が使っているのは python3.8
.
なんで python3.9
で探してるんだ..??
まず、私の python 環境がどうなっているか? をチェックしていく。
私は Mac を使っていて 、Mac には標準で python 2.x
が入っている。
sudachi@DaiMac:~ $ python -V
Python 2.7.16
(便宜上、今後この python を「システムの python」と表現することがあるかもしれないことに注意する)
しかし、今や python は 3系がメイン。
ということで brew
で python@3.8
だの python@3.9
だのを入れたりしていた。
ここで、ちょっと余計な小咄を挟むが、
私の認識では、3.8
を入れて使っているつもりだった。
しかし、いつの間にか ( brew update
などの結果か?) python@3.9
が入っていたことがあって、
これを手動で 3.8
に下げた、という経緯がある。
そして .bashrc
に以下のようなエイリアスを張って python 3.x
を使うようにしていた。
# Python alias
alias python="python3"
alias pip="pip3"
ちなみに brew では、以下のようにしてインストールしたり、アンインストールしたりしていた。
まず brew 経由でインストールできる python の一覧を見る
sudachi@DaiMac:~$ brew search python
==> Formulae
app-engine-python gst-python python-markdown python@3.7 wxpython
boost-python ipython python-tabulate python@3.8
boost-python3 micropython python-tk@3.9 python@3.9
bpython ptpython python-yq reorder-python-imports
==> Casks
awips-python kk7ds-python-runtime mysql-connector-python
If you meant "python" specifically:
It was migrated from homebrew/cask to homebrew/core.
python@3.8
のインストール
sudachi@DaiMac:~$ brew install python@3.{{x}}
これで python3
がインストールされる。
ログを見ると /usr/local/bin/python3
に入るらしい。
この python3
に1つ前で書いたエイリアスを効かせることで、python
のみで python3
を呼び出して使っていた。
(補足だが、いろんなプロジェクト間でのパッケージ管理は venv
を使っていた。
python -m venv venv
)
さて、ここで話を戻して、問題の続きといく。
(解決した後なので、整理すると) 問題の核は次のようなことであった。
- 私が
powerline-status
を導入したのはpython@3.9
に切り替わっている間のこと - つまり、
pip install powerline-status
をするとpython@3.9
に紐づいた pip が呼び出され、3.9
用のライブラリがインストールされる - それに気がつかずに
python@3.9
をpython@3.8
に落とした (もともと自分で入れたつもりだったのは3.8
だったため) - tmux の設定で
powerline-config
を呼ぼうとすると、python3.8
しかないのに、呼ばれるライブラリはpython3.9
用なので「呼び出せない / 効かない」とか「pip (python3.8の) install powerline-status
しても、呼ばれるのは powerline-status の python3.9` 用で変」みたいな問題が発生
ということが起きていた。
(直してしまったので) 再現してみる
$ brew install python@3.9
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 2 taps (homebrew/core and homebrew/cask).
==> Updated Formulae
Updated 92 formulae.
==> Updated Casks
Updated 114 casks.
==> Downloading https://homebrew.bintray.com/bottles/python%403.9-3.9.4.catalina.bottle.tar.gz
==> Downloading from https://d29vzk4ow07wi7.cloudfront.net/225b1f2e9bbc2d751abb0a539e9c231769370136649f7d94191114248bdf4d39?response-con
######################################################################## 100.0%
==> Pouring python@3.9-3.9.4.catalina.bottle.tar.gz
==> /usr/local/Cellar/python@3.9/3.9.4/bin/python3 -m ensurepip
==> /usr/local/Cellar/python@3.9/3.9.4/bin/python3 -m pip install -v --no-deps --no-index --upgrade --isolated --target=/usr/local/lib/p
==> Caveats
Python has been installed as
/usr/local/bin/python3
Unversioned symlinks `python`, `python-config`, `pip` etc. pointing to
`python3`, `python3-config`, `pip3` etc., respectively, have been installed into
/usr/local/opt/python@3.9/libexec/bin
You can install Python packages with
pip3 install <package>
They will install into the site-package directory
/usr/local/lib/python3.9/site-packages
tkinter is no longer included with this formula, but it is available separately:
brew install python-tk@3.9
See: https://docs.brew.sh/Homebrew-and-Python
==> Summary
🍺 /usr/local/Cellar/python@3.9/3.9.4: 3,047 files, 54.2MB
Removing: /Users/sudachi/Library/Caches/Homebrew/python@3.9--3.9.2_4.catalina.bottle.tar.gz... (13.6MB)
powerline-status
をインストール
$ pip install powerline-status # <= ここで呼ばれるのは python3.9 の pip
$ pip list # (python3.9 の pip)
Package Version
---------------- -------
pip 21.0.1
powerline-status 2.7 # <= powerline-status をインストールした
setuptools 54.2.0
wheel 0.36.2
ここで tmux を起動すると powerline
が効く。
$ brew list | grep python
python@3.9
ここで python@3.9
が入っているのは不本意なので、python@3.8
に落とす
$ brew uninstall --ignore-dependencies python@3.9
Uninstalling /usr/local/Cellar/python@3.9/3.9.4... (3,063 files, 54.3MB)
$ brew list | grep python
$ brew install python@3.8
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 1 tap (homebrew/core).
==> Updated Formulae
Updated 8 formulae.
==> Downloading https://homebrew.bintray.com/bottles/python%403.8-3.8.9.catalina.bottle.tar.gz
==> Downloading from https://d29vzk4ow07wi7.cloudfront.net/65a3d5fa32b16df0886c7390e992f4948b51ce56d10e57bd05895e5795efe0fd?response-con
######################################################################## 100.0%
==> Pouring python@3.8-3.8.9.catalina.bottle.tar.gz
==> /usr/local/Cellar/python@3.8/3.8.9/bin/python3 -s setup.py --no-user-cfg install --force --verbose --install-scripts=/usr/local/Cell
==> /usr/local/Cellar/python@3.8/3.8.9/bin/python3 -s setup.py --no-user-cfg install --force --verbose --install-scripts=/usr/local/Cell
==> /usr/local/Cellar/python@3.8/3.8.9/bin/python3 -s setup.py --no-user-cfg install --force --verbose --install-scripts=/usr/local/Cell
==> Caveats
Python has been installed as
/usr/local/opt/python@3.8/bin/python3
Unversioned symlinks `python`, `python-config`, `pip` etc. pointing to
`python3`, `python3-config`, `pip3` etc., respectively, have been installed into
/usr/local/opt/python@3.8/libexec/bin
You can install Python packages with
/usr/local/opt/python@3.8/bin/pip3 install <package>
They will install into the site-package directory
/usr/local/lib/python3.8/site-packages
See: https://docs.brew.sh/Homebrew-and-Python
python@3.8 is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.
If you need to have python@3.8 first in your PATH, run:
echo 'export PATH="/usr/local/opt/python@3.8/bin:$PATH"' >> /Users/sudachi/.bash_profile
For compilers to find python@3.8 you may need to set:
export LDFLAGS="-L/usr/local/opt/python@3.8/lib"
For pkg-config to find python@3.8 you may need to set:
export PKG_CONFIG_PATH="/usr/local/opt/python@3.8/lib/pkgconfig"
==> Summary
🍺 /usr/local/Cellar/python@3.8/3.8.9: 4,376 files, 71.4MB
$ brew list | grep python
python@3.8
$ python
Python 3.8.2 (default, Sep 24 2020, 19:37:08)
[Clang 12.0.0 (clang-1200.0.32.21)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
ここで powerline-status
が入ってるのかな? と pip
を呼ぶと python3.8
に紐づいた pip
が呼ばれる
$ pip list # <= python3.8 の pip が呼ばれる
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
Package Version
---------- -------
pip 21.0.1
setuptools 41.2.0
six 1.15.0
wheel 0.33.1
入ってないじゃーん、と思って pip install powerline-status
してしまう
$ pip install powerline-status # (python3.8 の pip)
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
Defaulting to user installation because normal site-packages is not writeable
Collecting powerline-status
Using cached powerline_status-2.7-py3-none-any.whl
Installing collected packages: powerline-status
Successfully installed powerline-status-2.7
$ pip list # (python3.8 の pip)
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
Package Version
---------------- -------
pip 21.0.1
powerline-status 2.7
setuptools 41.2.0
six 1.15.0
wheel 0.33.1
ここで tmux を起動しても powerline
は効かない!!
(何故なら、tmux から呼んでいる powerline は python3.9 用のものなのに、python3.8 用のがインストールされているからである)
さてここで tmux の設定ファイルで呼んでいる powerline を思い出してみる。
run-shell "powerline-config tmux setup"
試しに powerline-config
を呼んでみる
$ powerline-config
-bash: /usr/local/bin/powerline-config: /usr/local/opt/python@3.9/bin/python3.9: bad interpreter: No such file or directory
python3.9
のが呼ばれていることがわかる。
この状態になってしまうとめんどくさい。(めんどくさかった)
直す。
python3.8
でインストールした powerline-status
を消す。
$ pip3 list
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
Package Version
---------------- -------
pip 21.0.1
powerline-status 2.7
setuptools 41.2.0
six 1.15.0
wheel 0.33.1
$ pip3 uninstall powerline-status
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
Found existing installation: powerline-status 2.7
Uninstalling powerline-status-2.7:
Would remove:
/Users/sudachi/Library/Python/3.8/bin/powerline
/Users/sudachi/Library/Python/3.8/bin/powerline-config
/Users/sudachi/Library/Python/3.8/bin/powerline-daemon
/Users/sudachi/Library/Python/3.8/bin/powerline-lint
/Users/sudachi/Library/Python/3.8/bin/powerline-render
/Users/sudachi/Library/Python/3.8/lib/python/site-packages/powerline/*
/Users/sudachi/Library/Python/3.8/lib/python/site-packages/powerline_status-2.7.dist-info/*
Proceed (y/n)? y
Successfully uninstalled powerline-status-2.7
python@3.8
をアンインストールする。
$ brew list | grep python
python@3.8
$ brew uninstall python@3.8
Uninstalling /usr/local/Cellar/python@3.8/3.8.9... (4,376 files, 71.4MB)
$ brew list | grep python
python@3.9
をインストールする。
$ brew install python@3.9
$ brew list | grep python
python@3.9
$ python3 -V
Python 3.9.4
pip list
してみると、確かに powerline-status
が入っている。
$ pip3 list
Package Version
---------------- -------
pip 21.0.1
powerline-status 2.7
setuptools 54.2.0
wheel 0.36.2
python3.9
に紐づいているパッケージ全部消してしまおう
(どうせあとでで消すので)
$ pip3 freeze > delreq.txt
$ cat delreq.txt
powerline-status==2.7
$ pip3 uninstall -r delreq.txt
Found existing installation: powerline-status 2.7
Uninstalling powerline-status-2.7:
Would remove:
/usr/local/bin/powerline
/usr/local/bin/powerline-config
/usr/local/bin/powerline-daemon
/usr/local/bin/powerline-lint
/usr/local/bin/powerline-render
/usr/local/lib/python3.9/site-packages/powerline/*
/usr/local/lib/python3.9/site-packages/powerline_status-2.7.dist-info/*
Proceed (y/n)? y
Successfully uninstalled powerline-status-2.7
( powerline-status
だけでしたね。環境をわざわざ再現したのでそれはそうか.. )
パッケージが削除されていることを確認して
$ pip3 list
Package Version
---------- -------
pip 21.0.1
setuptools 54.2.0
wheel 0.36.2
python@3.9
をアンインストールする
$ brew list | grep python
python@3.9
$ brew uninstall python@3.9
Error: Refusing to uninstall /usr/local/Cellar/python@3.9/3.9.4
because it is required by google-cloud-sdk, which is currently installed.
You can override this and force removal with:
brew uninstall --ignore-dependencies python@3.9
$ brew uninstall --ignore-dependencies python@3.9
Uninstalling /usr/local/Cellar/python@3.9/3.9.4... (3,056 files, 54.2MB)
$ brew list | grep python
ここまでやると python がこれだけになる
$ python [tab]
python
python python2 python2.7-config pythonw
python-config python2.7 python3 pythonw2.7
ほとんど 2系だが、1つだけ 3系のものがある。
これについて以下でちょっと触れる。
$ which python
/usr/bin/python
$ python
WARNING: Python 2.7 is not recommended.
This version is included in macOS for compatibility with legacy software.
Future versions of macOS will not include Python 2.7.
Instead, it is recommended that you transition to using 'python3' from within Terminal.
Python 2.7.16 (default, Jun 5 2020, 22:59:21)
[GCC 4.2.1 Compatible Apple LLVM 11.0.3 (clang-1103.0.29.20) (-macos10.15-objc- on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
python
で呼ばれるのも 2.x である。
残っていている、python3
については
$ which python3
/usr/bin/python3
$ python3
Python 3.8.2 (default, Sep 24 2020, 19:37:08)
[Clang 12.0.0 (clang-1200.0.32.21)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
このようにして呼べるのだが、これは xcode-select --install
すると入ってくるものらしい。
もちろん pip3
も付属している
$ which pip3
/usr/bin/pip3
$ pip3 list
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
Package Version
---------- -------
pip 21.0.1
setuptools 41.2.0
six 1.15.0
wheel 0.33.1
Python 3 インストール のページを xcode
とかで検索すると
macOS Big Sur では,ターミナルに xcode-select --install と打ち込んでコマンドラインツールをインストールすると,universal binary の Python 3.8.2 が入ります。
という一文が出てくる。
(私の使っているOSは Catalina
なのだが.. version も一致しているし、インストールされるディレクトリも同じだし、たぶんこれだろうと思う)
最後に。
「どういう風にして python 環境を (mac 上に) 作れば、今回のようなことが起きないか」を考える
これに関して、現状の私の知識と理解で導き出せる解決策として
- システムの python は基本的に呼ばない
- 仮想環境を作って分離する
ことだと思う。
この「仮想環境」というところがむずかしい。
python において「仮想環境」はいろんな意味 (役割?) を持つと思う。
python 仮想環境 [検索]
とかすると
pyenv
とか anaconda
とか venv
とか pipenv
とか virtualenv
とか...
たくさん出てくると思うが
まずやることは python
自体を仮想環境で管理する ことだと思う。
私が知っている (使ったことある) 中で、 python
自体を仮想環境で管理する ことができるのは
pyenv
か anaconda
である。
つまり、さっき出した例でいうと
-
pyenv
やanaconda
と -
venv
やpipenv
,virtualenv
と
では やろうとしていることが違う というところに注意が必要なのである。
私はこの違いを理解せずに venv
を利用して「python を仮想環境で使っているつもり」になっていたために今回このような事故を起こしてしまった。
私のような悲しい事故に合う人が今後困らないように ここに墓標を立てる。R.I.P
私は以前まで、anaconda
を好んで使っていた。
GUI コンソールが付属するのがわかりやすいし、conda
コマンドを介して CLI で仮想環境を管理することもできる。
しかし、動作が重かったり、プロンプトが汚れたりすることが気になった。
(base) sudachi@DaiMac:~ $
⬆️ ターミナルで python 以外のことをしているときも、常にこの (base)
というのがプロンプトに表示されて 片時も頭を話してくれない。メンヘラか。 とにかく じゃま なのである..
そこで pyenv
を使うことにした。
以下を参考にインストールする
$ which brew-all
/Users/sudachi/mybin/brew-all
$ cat `which brew-all`
#!/bin/bash
brew update
brew upgrade
brew cleanup
brew doctor
$ brew-all
-
pyenv
のインストール
$ brew install pyenv
設定ファイルに次の一行を追加 (私は ~/.bashrc
に書いた)
eval "$(pyenv init -)"
設定ファイルの読み込み
$ exec $SHELL -l
# or
$ source ~/.bashrc
動作確認
$ pyenv
pyenv 1.2.26
Usage: pyenv <command> [<args>]
Some useful pyenv commands are:
--version Display the version of pyenv
commands List all available pyenv commands
...
which Display the full path to an executable
See `pyenv help <command>' for information on a specific command.
For full documentation, see: https://github.com/pyenv/pyenv#readme
- 利用できる python のバージョンをチェック
$ pyenv versions
* system (set by /Users/sudachi/.pyenv/version)
インストール直後では system しかない。
- インストール可能な python の一覧を取得
$ pyenv install -l
-
python 3.8.9
(3.8
の最新版) をインストール
$ pyenv install 3.8.9
- インストールすると利用可能なバージョンが増える
pyenv versions
system
* 3.8.9 (set by /Path/to/some/where/.python-version)
- ローカル / グローバルに使用する
$ pyenv local 3.8.9
$ pyenv global 3.8.9
また、あるプロジェクトの配下で
$ pyenv local 3.8.9
とすると
$ python -V
Python 3.8.9
となって、プロジェクト毎にも python のバージョンを分離することができる。
私の個人的な感想だが
私は、go
の仮想環境を goenv
で管理して使っているの。
pyenv
は、これと使い心地が一緒で嬉しい。
( 他にも ruby の仮想環境がを rbenv
が提供しているらしい。
どこかでこれが発端だという記述を見たような記憶もあるが、どこで見たか定かでない.. )
「使い心地が似ている / 一緒だ」というのは学習コストの面でとても助かる。
1つ覚えれば加速度的に使い方の理解が進むので、これからも使っていくことだろうと思う。
さて、ここで終わりたいところなのだがもう一息。
python
自体を仮想環境で管理することができた。
しかし、現在の状態で pip
を呼び出すと、~/.pyenv/shims/python
に紐づいた pip
が呼ばれる。
$ which pip
/Users/sudachi/.pyenv/shims/pip
つまり、ずっと global
を使っていたり
異なる2つのプロジェクトで、同じバージョンの python (pyenvの) を pyenv local
して使ったりすると、パッケージのバージョンが競合したりする可能性がある。
この問題を回避するために使うのが、2つ目の意味での「仮想環境」なのであった。
venv や pipenv, virtualenv
伏線回収
この仮想環境については、引き続き venv
を使っていこうと思う。
使っていて特に問題はないし、公式だ、というところでチョイスしている。
(個人的にはこのチョイス。組織的に規定されているものがあれば、もちろんそれを使う)
使い方などを、プロジェクト作成ベースで見ていこう
- テキトーに練習用のディレクトリを作成する。
$ mkdir -p ~/Desktop/tmp
$ cd ~/Desktop/tmp
-
pyenv
を使って利用する python のバージョンを指定する
$ pyenv local 3.8.9
-
venv
を使って、パッケージの仮想環境を作成し、venv/bin/activate
を読み込んで仮想環境をアクティベートする
$ python -m venv venv
$ source venv/bin/activate
ここで、何かインストールしたいライブラリがあるとしよう。
ここでは numpy
を例にとって以下進める。
- インストールされているパッケージのリストを確認
(venv) sudachi@DaiMac:tmp$ pip list
Package Version
---------- -------
pip 20.2.3
setuptools 49.2.1
WARNING: You are using pip version 20.2.3; however, version 21.0.1 is available.
You should consider upgrading via the '/Users/sudachi/Desktop/tmp/venv/bin/python -m pip install --upgrade pip' command.
# pip 自身を upgrade しろ、と言われたのでする
(venv) sudachi@DaiMac:tmp$ pip install --upgrade pip
Collecting pip
Using cached pip-21.0.1-py3-none-any.whl (1.5 MB)
Installing collected packages: pip
Attempting uninstall: pip
Found existing installation: pip 20.2.3
Uninstalling pip-20.2.3:
Successfully uninstalled pip-20.2.3
Successfully installed pip-21.0.1
- インストールしたいパッケージ (今回は
numpy
のインストール)
(venv) sudachi@DaiMac:tmp$ pip install numpy
Collecting numpy
Downloading numpy-1.20.2-cp38-cp38-macosx_10_9_x86_64.whl (16.0 MB)
|████████████████████████████████| 16.0 MB 5.0 MB/s
Installing collected packages: numpy
Successfully installed numpy-1.20.2
# 確認
(venv) sudachi@DaiMac:tmp$ pip list
Package Version
---------- -------
numpy 1.20.2
pip 21.0.1
setuptools 49.2.1
- パッケージをインストールしたら
requirements.txt
などを更新する癖をつけておくといいかもしれない
(個人的にvenv
を使う過程でそういう習慣がある..というポジショントーク..)
(venv) sudachi@DaiMac:tmp$ pip freeze
numpy==1.20.2
(venv) sudachi@DaiMac:tmp$ pip freeze > requirements.txt
- テキトーなプログラムを
~/Desktop/tmp/main.py
に作った
import numpy as np
print( np.random.randint(0, 10) )
-
venv on pyenv
で実行 (できる)
(venv) sudachi@DaiMac:tmp$ python main.py
9 # 割と大きめの目が出て草
- 試しに仮想環境をデアクティベートしてみる
(ここで (venv) が出てこなくなる、というのも嬉しいポイント)
(venv) sudachi@DaiMac:tmp$ deactivate
- これで実行してみても、
numpy
がないって怒られる
sudachi@DaiMac:tmp$ python main.py
Traceback (most recent call last):
File "main.py", line 1, in <module>
import numpy as np
ModuleNotFoundError: No module named 'numpy'
何故なら pyenv
の python に紐づいている pip
には numpy
がインストールされておらず
sudachi@DaiMac:tmp$ pip list
Package Version
---------- -------
pip 20.2.3
setuptools 49.2.1
WARNING: You are using pip version 20.2.3; however, version 21.0.1 is available.
You should consider upgrading via the '/Users/sudachi/.pyenv/versions/3.8.9/bin/python3.8 -m pip install --upgrade pip' command.
あくまでも venv on pyenv
の python の pip
でインストールしたからである。
なんか、トンチみたいになってしまって申し訳ない..
このようにして、pyenv
の python を汚さずに使うことができる。
しばらくはこの環境で利用してみようと思っている。