Closed
21

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系がメイン。
ということで brewpython@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 )

さて、ここで話を戻して、問題の続きといく。

(解決した後なので、整理すると) 問題の核は次のようなことであった。

  1. 私が powerline-status を導入したのは python@3.9 に切り替わっている間のこと
  2. つまり、pip install powerline-status をすると python@3.9 に紐づいた pip が呼び出され、3.9 用のライブラリがインストールされる
  3. それに気がつかずに python@3.9python@3.8 に落とした (もともと自分で入れたつもりだったのは 3.8 だったため)
  4. 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 自体を仮想環境で管理する ことができるのは
pyenvanaconda である。

つまり、さっき出した例でいうと

  • pyenvanaconda
  • venvpipenv, 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 を汚さずに使うことができる。

しばらくはこの環境で利用してみようと思っている。

このスクラップは13日前にクローズされました
ログインするとコメントできます