前言
最近準備要開發新的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 | if command -v pyenv 1>/dev/null 2>&1; then |
重新啟動shell並查看pyenv
安裝狀態
1 | pipenv -v |
1 | Usage: pipenv [OPTIONS] COMMAND [ARGS]... |
Ubuntu安裝
下載Pyenv
1 | git clone git://github.com/yyuu/pyenv.git ~/.pyenv |
編輯並新增下列設定至你所使用的shell設定檔(.bashrc
, .zshrc
, .bash_profile
)
1 | export PYENV_ROOT="$HOME/.pyenv" |
初始化系統參數
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 | * system (set by /Users/a35205905/.pyenv/version) |
切換python版本
切換整個系統上的python版本
1 | pyenv global <version> |
在當前目錄切換python版本,並建立.python-version
存放版號
1 | pyenv local <version> |
在當前shell的session裡切換版本,權重優先於global
&local
1 | $ pyenv shell <version> |
查看python版本
1 | global |
pipenv
順帶一提,pipenv
已成為Python官方推薦的套件管理工具,pipenv
不但解決了套件相依的問題
還一併整合了virtualenv的功能,如此一來我們更能專注於在開發本身上就好,讚讚!
pipenv
會透過自動產生的兩個檔案進行套件管理,分別為:
Pipfile
:存放開發&正式環境中所有套件的設定檔Pipfile.lock
:存放所有套件版、相依套件版本、hash值的設定檔
安裝
1 | pip3 install pipenv |
自定義虛擬環境
在建立虛擬環境之前,我們要先知道pipenv預設目錄為/home/$username/.local/share/virtualenvs
因此如果要自定義虛擬環境的目錄有以下兩個做法
設置在該專案根目錄下,透過
PIPENV_VENV_IN_PROJECT
環境變數1
export PIPENV_VENV_IN_PROJECT=1
設定在指定的目錄,透過
export WORKON_HOME
環境變數1
export WORKON_HOME=~/.venvs
要至shell設定檔(
.bashrc
,.zshrc
,.bash_profile
)設定環境變數
建立虛擬環境
建立虛擬環境
1 | pipenv install --python <version> |
你可以選擇透過剛剛pyenv切換好版本
這時候會有以下兩個情況:
- 若你還沒有
Pipfile
&Pipfile.lock
,它將會自動產生這兩個檔案 - 若你已經有
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 | [packages] |
你還可以指定套件的版本
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 | [[source]] |
然而你執行升級套件指令
1 | pipenv update django |
卻發現什麼事都沒做
1 | Locking [dev-packages] dependencies... |
這是因為update
這個指令是只根據你的Pipfile的套件版本來決定是否要升級!
因此如果你想升級套件的話,你必須先編輯Pipfile裡的套件版本
1 | ... |
若是將版本設為*代表升級成最新的版本
這時候再下一次升級指令
1 | pipenv update django |
你會發現下面的進度條變成2/2,這代表包含套件本身及相依套件共兩個套件同時被升級或安裝
1 | Locking [dev-packages] dependencies... |
這時你用圖形化顯示更能看清楚整個套件的關係圖
1 | pipenv graph |
1 | Django==3.2.5 |
而你一樣可以批次更改多個套件的版本在一次升級
1 | pipenv update |
降級套件
這時候你可能會想說那降級是不是只要把版號改小就好,很遺憾的是pipenv
不支援這樣的功能
但是我們還是能透過最原始的做法來達到目的
首先先將套件移除
1 | pipenv uninstall <package> |
再重新安裝指定版本的套件
1 | pipenv install <package>==<version> |