Ricky 叩叮俱樂部

在開始之前,先來杯長島冰茶吧~

0%

macOS+pipenv+pyenv

前言

最近準備要開發新的Python專案時,發現自己原先用pip+virtualenv的方式已經有點難管理各個版本的套件了
會有這樣的感覺是因為之前參與其他專案時發現無論是Laravel的composer.json/composer.lock
或是Vue的package.json/yarn.lock都能很有效的管理套件本身的相依問題
而要達到這點,進一步的還需要在本機與測試機版本相同的情況下會是更好
雖然能達成的方法有很多,但還是想以pipenv+pyenv來實做看看

本篇是以該教材作為參考依據

Pyenv

macOS安裝

在macOS中使用Homebrew來安裝Pyenv

1
$ brew install pyenv

編輯並新增下列設定至你所使用的shell設定檔(.bashrc, .zshrc, .bash_profile)

1
2
3
if command -v pyenv 1>/dev/null 2>&1; then
eval "$(pyenv init -)"
fi

重新啟動shell並查看pyenv安裝狀態

1
$ pipenv -v
1
2
3
4
5
6
7
8
9
10
11
12
Usage: pipenv [OPTIONS] COMMAND [ARGS]...

Options:
--where Output project home information.
--venv Output virtualenv information.
--py Output Python interpreter information.
--envs Output Environment Variable options.
--rm Remove the virtualenv.
--bare Minimal output.
--completion Output completion (to be executed by the
shell).
...

Ubuntu安裝

下載Pyenv

1
$ git clone git://github.com/yyuu/pyenv.git ~/.pyenv

編輯並新增下列設定至你所使用的shell設定檔(.bashrc, .zshrc, .bash_profile)

1
2
3
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

初始化系統參數

1
$ source ~/.bash_profile

安裝相關依賴套件

1
$ sudo apt install make build-essential llvm libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl libncurses5-dev xz-utils libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev tk-dev

新增python版本

查看在pyenv上的所有可安裝的python版本

1
$ pyenv install --list

安裝指定的python版本

1
$ pyenv install <version>

查看本機已安裝的所有python版本

1
$ pyenv versions
1
2
3
* system (set by /Users/a35205905/.pyenv/version)
3.6.9
3.9.4

切換python版本

切換整個系統上的python版本

1
$ pyenv global <version>

在當前目錄切換python版本,並建立.python-version存放版號

1
$ pyenv local <version>

在當前shell的session裡切換版本,權重優先於global&local

1
$ pyenv shell <version>

查看python版本

1
2
3
4
5
6
7
8
# global
$ pyenv global

# local
$ pyenv local

# shell
$ pyenv shell

pipenv

順帶一提,pipenv已成為Python官方推薦的套件管理工具pipenv不但解決了套件相依的問題
還一併整合了virtualenv的功能,如此一來我們更能專注於在開發本身上就好,讚讚!

pipenv會透過自動產生的兩個檔案進行套件管理,分別為:

  • Pipfile:存放開發&正式環境中所有套件的設定檔
  • Pipfile.lock:存放所有套件版、相依套件版本、hash值的設定檔

安裝

1
$ pip3 install pipenv

自定義虛擬環境

在建立虛擬環境之前,我們要先知道pipenv預設目錄為/home/$username/.local/share/virtualenvs
因此如果要自定義虛擬環境的目錄有以下兩個做法

  1. 設置在該專案根目錄下,透過PIPENV_VENV_IN_PROJECT環境變數

    1
    export PIPENV_VENV_IN_PROJECT=1
  2. 設定在指定的目錄,透過export WORKON_HOME環境變數

    1
    export WORKON_HOME=~/.venvs

要至shell設定檔(.bashrc, .zshrc, .bash_profile)設定環境變數

建立虛擬環境

建立虛擬環境

1
pipenv install --python <version>

你可以選擇透過剛剛pyenv切換好版本

這時候會有以下兩個情況:

  1. 若你還沒有Pipfile&Pipfile.lock,它將會自動產生這兩個檔案
  2. 若你已經有Pipfile&Pipfile.lock,它將會安裝設定檔裡的所有套件

設定檔範例:

  • Pipfile

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [[source]]
    url = "https://pypi.org/simple"
    verify_ssl = true
    name = "pypi"

    [packages]

    [dev-packages]

    [requires]
    python_version = "3.9"
  • Pipfile.lock

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    {
    "_meta": {
    "hash": {
    "sha256": "a36a5392bb1e8bbc06bfaa0761e52593cf2d83b486696bf54667ba8da616c839"
    },
    "pipfile-spec": 6,
    "requires": {
    "python_version": "3.9"
    },
    "sources": [
    {
    "name": "pypi",
    "url": "https://pypi.org/simple",
    "verify_ssl": true
    }
    ]
    },
    "default": {},
    "develop": {}
    }

若顯示ValueError: unknown locale: UTF-8等錯誤訊息,表示系統需要設定LANG環境變數

1
export LANG=en_US.UTF-8 // ~/.bashrc or ~/.zshrc

你也可以刪除虛擬環境

1
$ pipenv --rm

requirements.txt

若在目錄中有包含requirements.txt,那麼pipenv就會自動安裝所有套件
並且同樣的會產生Pipfile&Pipfile.lock,完全可以無痛從pip轉換成pipenv

1
$ pipenv install

你也可以指定某一個路徑下的requirements.txt

1
$ pipenv install -r <path>/requirements.txt

而要從手動產生requirements.txt也很簡單

1
$ pipenv pipenv lock -r

切換虛擬環境

進入虛擬環境

1
$ pipenv shell

退出虛擬環境

1
$ exit

安裝套件

安裝套件

1
$ pipenv install <package>==<verison>

在沒有指定版本的情況下你可以看到Pipfile&Pipfile.lock被更新了
Pipfile

1
2
[packages]
<your package> = "*"

你還可以指定套件的版本

1
$ pipenv install <package>

安裝開發用的套件

1
$ pipenv install <package> --dev

這時候你將虛擬環境砍掉,重新執行pipenv install時,會自動忽略[dev-packages]裡的所有套件

查看所有套件以及相依套件關係

1
$ pipenv graph

確認你的相依套件有無安全漏洞

1
pipenv check

移除套件

1
$ pipenv uninstall <package>

升級套件

假設你今天安裝了特定版本的套件,像是

1
$ pipenv install django==2.2

那麼你現在Pipfile會是這樣

1
2
3
4
5
6
7
8
9
10
11
12
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
django = "==2.2"

[dev-packages]

[requires]
python_version = "3.9"

然而你執行升級套件指令

1
$ pipenv update django

卻發現什麼事都沒做

1
2
3
4
5
6
7
8
9
10
11
Locking [dev-packages] dependencies...
Locking [packages] dependencies...
Building requirements...
Resolving dependencies...
✔ Success!
Updated Pipfile.lock (24b2dc)!
Installing dependencies from Pipfile.lock (24b2dc)...
🐍 ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 0/0 — 00:00:00
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
All dependencies are now up-to-date!

這是因為update這個指令是只根據你的Pipfile的套件版本來決定是否要升級!
因此如果你想升級套件的話,你必須先編輯Pipfile裡的套件版本

1
2
3
4
5
6
...

[packages]
django = "*"

...

若是將版本設為*代表升級成最新的版本

這時候再下一次升級指令

1
$ pipenv update django

你會發現下面的進度條變成2/2,這代表包含套件本身及相依套件共兩個套件同時被升級或安裝

1
2
3
4
5
6
7
8
9
Locking [dev-packages] dependencies...
Locking [packages] dependencies...
Building requirements...
Resolving dependencies...
✔ Success!
Updated Pipfile.lock (06f36b)!
Installing dependencies from Pipfile.lock (06f36b)...
🐍 ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 2/2 — 00:00:00
All dependencies are now up-to-date!

這時你用圖形化顯示更能看清楚整個套件的關係圖

1
$ pipenv graph
1
2
3
4
Django==3.2.5
- asgiref [required: >=3.3.2,<4, installed: 3.4.1]
- pytz [required: Any, installed: 2021.1]
- sqlparse [required: >=0.2.2, installed: 0.4.1]

而你一樣可以批次更改多個套件的版本在一次升級

1
$ pipenv update

降級套件

這時候你可能會想說那降級是不是只要把版號改小就好,很遺憾的是pipenv不支援這樣的功能
但是我們還是能透過最原始的做法來達到目的

首先先將套件移除

1
$ pipenv uninstall <package>

再重新安裝指定版本的套件

1
$ pipenv install <package>==<version>