1. 題引
1.1 pipx 是什么?
據官網介紹,pipx 是安裝並運行 Python 終端用戶應用(end-user applications)的工具。
終端用戶應用,其實可以理解為用 Python 編寫的命令行工具,可以直接從命令行調用的那種。
有點類似 Mac 下的 brew,類似 JavaScript 的 npx,和 pip 也很像,
只是專門用來安裝命令行工具庫。
pipx 之所以存在,是因為 Python 和 PyPI 支持開發者發布帶有”終端腳本入口“的代碼,
用戶可以在命令行調用 Python 代碼,使得這個 Python 包類似於一個獨立的應用。
1.2 pipx 的主要功能
pipx 支持如下功能:
將 Python 包安全地安裝在隔離環境中,同時又可以全局暴露出命令行的調用入口。
這樣可以避免依賴之間的沖突。
列舉、更新和刪除使用 pipx 安裝的包
在臨時環境中運行某個 Python 應用的最新版
pipx 需要 Python 3.6 及以上版本,同時必須已經安裝好了 pip。
1.3 為什么要使用poetry?
因為想使用pyproject.toml,並通過pyproject.toml進行依賴包管理.
目前pip還不支持,所以poetry是首選
1.4 為什么要使用pyproject.toml?
首先pytest、black、isort等常用工具都支持pyproject.toml了,
可以實現一個文件完成全項目的配置。
其次pyproject.toml是PEP中的內容,是將來的方向。
事實上,已經有越來越多的開源下項目使用pyproject.toml,因此我們也有必要學習了解一下
擴展閱讀:
2 安裝pipx
pipx會為安裝的每一個包自動創建隔離環境,並自動設置環境變量。
安裝的包能夠被執行,非常使用安裝那些命令行程序,
比如block、httpie、poetry。
首先在系統級python環境中安裝pipx
pip install pipx
將pipx的虛擬環境加入到環境變量里面
pipx ensurepath
按照此命令打印的說明,可以完成shell操作:
pipx completions
驗證安裝成功
pipx list
如果你尚未安裝任何軟件包,你將看到以下輸出:
nothing has been installed with pipx ?
2.1安裝 Python 包
以下是 Pipx 入門的一個例子
要全局安裝 Python 應用,例如 cowsay,請運行:
$ pipx install cowsay
此命令將自動創建虛擬環境,在其中安裝包並包的可執行文件放在 $PATH 中。
示例輸出:
installed package cowsay 2.0.3, Python 3.6.8
These binaries are now globally available
- cowsay
done! ✨ ? ✨
讓我們測試新安裝的 cowsay 程序:
$cowsay moon
____
| mooo |
====
\
\
^__^
(oo)\_______
(__)\ )\/\
||----w |
|| ||
在這里,它僅僅是一個例子。你可以安裝/測試任何其他的 Python 包。
再次列出pipx 安裝的Python 包
$ pipx list
示例輸出:
venvs are in C:\Users\admin\.local\pipx\venvs
apps are exposed on your $PATH at C:\Users\emijnae\.local\bin
package cowsay 4.0, Python 3.8.4
- cowsay.exe
Pipx 的默認虛擬環境位置是 ~/.local/pipx。這可以用環境變量 PIPX_HOME 覆蓋。
pipx 二進制文件的默認位置是 ~/.local/bin。
你可以使用 PIPX_BIN_DIR 環境變量覆蓋它。
如果要覆蓋 PIPX_BIN_DIR,只需運行 userpath append $PIPX_BIN_DIR,
確保它在你的路徑中。
讓我們繼續看看如何使用 Pipx 安裝 Python 應用。
使用 Pipx 在隔離環境中安裝和運行 Python 應用
2.2升級包
要升級指定的安裝包,只需執行以下操作:
$ pipx upgrade cowsay
要一次性升級所有已安裝的軟件包,請使用:
$ pipx upgrade-all
從臨時虛擬環境運行應用
有時,你可能希望運行特定的 Python 程序,但並不實際安裝它。
$ pipx run pycowsay moooo
在臨時隔離虛擬環境中運行 Python 應用
此命令實際上並不安裝指定程序,而是從臨時虛擬環境運行它。你可以使用此命令快速測試 Python 應用。
你甚至可以直接運行 .py 文件。
$ pipx run https://gist.githubusercontent.com/cs01/fa721a17a326e551ede048c5088f9e0f/raw/6bdfbb6e9c1132b1c38fdd2f195d4a24c540c324/pipx-demo.py
pipx is working!
2.3 卸載軟件包
可以使用以下命令卸載軟件包:
$ pipx uninstall cowsay
要刪除所有已安裝的包:
$ pipx uninstall-all
2.4 獲得幫助
要查看幫助部分,請運行:
$ pipx --help
就是這些了。如果你一直在尋找安全,方便和可靠的程序來安裝和運行 Python 應用,Pipx 可能是一個不錯的選擇。
3 安裝 配置poetry
3.1 安裝
可以使用python自帶的pip工具來安裝,但是這里我們使用pipx來安裝
pipx install poetry
installed package poetry 1.1.4, Python 3.9.0
These apps are now globally available
- poetry.exe
done!
安裝成功后,使用pipx檢查安裝效果
pipx list
venvs are in C:\Users\san\.local\pipx\venvs
apps are exposed on your $PATH at C:\Users\san\.local\bin
package poetry 1.1.4, Python 3.9.0
- poetry.exe
檢查一下是否安裝成功
poetry
Poetry version 1.1.10
USAGE
poetry [-h] [-q] [-v [<...>]] [-V] [--ansi] [--no-ansi] [-n] <command> [<arg1>] ... [<argN>]
ARGUMENTS
<command> The command to execute
<arg> The arguments of the command
GLOBAL OPTIONS
-h (--help) Display this help message
.......
自此,poetry就已經安裝好了。
我們是通過pipx安裝的poetry,日后也可以通過pipx 更新poetry:
pipx upgrade poetry
3.2配置設置
查詢當前所有配置
$ poetry config list
cache-dir = "/home/$user/.cache/pypoetry"
experimental.new-installer = true
installer.parallel = true
virtualenvs.create = true
virtualenvs.in-project = null
virtualenvs.path = "{cache-dir}/virtualenvs" # /home/$user/.cache/pypoetry/virtualenvs
查詢單個配置
poetry config virtualenvs.path
添加或者更新配置
poetry config virtualenvs.in-project true
刪除配置
poetry config virtualenvs.path --unset
查看可用軟件包
根據 poetry.lock 列出所有可用的軟件包,並不是根據 pyproject.toml 文件的 [tool.poetry.dependencies]
poetry show
查看某個包的詳細信息
$ poetry show fastapi
name : fastapi
version : 0.61.2
description : FastAPI framework, high performance, easy to learn, fast to code, ready for production
dependencies
- pydantic >=1.0.0,<2.0.0
- starlette 0.13.6
options
--no-dev:不要列出開發依賴項
--tree:樹的形式列出依賴項
--latest (-l):顯示最新版本
--outdated (-o):顯示最新版本,但僅適用於過時的軟件包
4. 在項目中使用 poetry
4.1新建項目
new
通過創建適合大多數項目的目錄結構來啟動新的Python項目
poetry new my-package
my-package 是路徑,默認目錄結構:
my-package
├── pyproject.toml # poetry 用於管理項目的 all-in-one 配置文檔.
├── README.rst # 說明文檔
├── my_package # poetry 會幫你將包名調整為下划線格式.
│ └── __init__.py # 請在該目錄下編寫你的業務邏輯.
└── tests # 測試模塊.
├── __init__.py
└── test_my_package.py
它有如下參數:
OPTIONS
--name Set the resulting package name.自定義項目名稱
--src Use the src layout for the project. 使用 src 目錄
比如創建一個名字為my-folder的項目,並使用src目錄:
poetry new my-folder --name my-package --src
目錄結構
my-folder
├── pyproject.toml
├── README.rst
├── src
│ └── my_package
│ └── __init__.py
└── tests
├── __init__.py
└── test_my_package.py
4.2初始化一個項目
poetry init
如果想在已存在的 Python 項目使用 poetry,可以用 init 命令,poetry 會以交互方式創建 pyproject.toml 文件
在項目的根目錄,執行poetry是, 並一路回車
poetry init
This command will guide you through creating your pyproject.toml config.
Package name [apipractice]:
Version [0.1.0]:
Description []:
Author []:
License []:
Compatible Python versions [^3.9]:
Would you like to define your main dependencies interactively? (yes/no) [yes]
You can specify a package in the following forms:
- A single name (requests)
- A name and a constraint (requests@^2.23.0)
- A git url (git+https://github.com/python-poetry/poetry.git)
- A git url with a revision (git+https://github.com/python-poetry/poetry.git#develop)
- A file path (../my-package/my-package.whl)
- A directory (../my-package/)
- A url (https://example.com/packages/my-package-0.1.0.tar.gz)
Search for package to add (or leave blank to continue):
Would you like to define your development dependencies interactively? (yes/no) [yes]
Search for package to add (or leave blank to continue):
Generated file
[tool.poetry]
name = "apipractice"
version = "0.1.0"
description = ""
authors = ["$user <email@github.com>"]
[tool.poetry.dependencies]
python = "^3.9"
[tool.poetry.dev-dependencies]
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
Do you confirm generation? (yes/no) [yes]
在Do you confirm generation? (yes/no) [yes] 后按下回車之后,將會在當前目錄生成pyproject.toml,內容如下
[tool.poetry]
name = "apipractice" # 項目名稱,默認會填寫當前目錄的名稱
version = "0.1.0" # 默認版本
description = "" # 對本項目簡單的描述
authors = ["$user <email@github.com>"]
[tool.poetry.dependencies]
python = "^3.9" # 版本依賴包括python版本和第三方庫
[tool.poetry.dev-dependencies] # 開發模式下依賴的第三方庫
[build-system] # 默認構建項目時使用的內容,一般不用改
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
我是一只回車沒有自己輸入東西的
options
--name:包的名稱
--description:包的描述
--author:包的作者
--python:兼容的 Python 版本
--dependency:需要具有版本約束的包,格式 foo:1.0.0
--dev-dependency:開發需求
生成 pyproject 已有的字段 和 options 是可以對齊的
4.3 安裝依賴
從當前項目讀取 pyproject.toml 文件,解析依賴項 [tool.poetry.dependencies] 並安裝它們
poetry install
如果當前目錄中有 poetry.lock 文件,它將使用其中的確切版本,而不是解析它們, 這確保使用庫的每個人都將獲得相同版本的依賴項
如果沒有 poetry.lock 文件,poetry 將在依賴項解析后創建一個
重點
默認會安裝 [tool.poetry.dependencies] 和 [tool.poetry.dev-dependencies] 下所有強制安裝的(不帶 optional)依賴項
它有如下參數
--no-dev 不安裝開發依賴項 [tool.poetry.dev-dependencies]
poetry install --no-dev
--remove-untracked 移除 poetry.lock 文件中不再存在的舊依賴項
poetry install --remove-untracked
-E|--extras 指定安裝的包
poetry install --extras
--no-root 不要安裝根目錄包
poetry install --no-root
同時,記得上面提到的這個參數
poetry config virtualenvs.in-project true
如果沒有設置,可以配置一下,但是最好的方法是在項目目錄下創建一個文件poetry.toml,寫下如下內容:
[virtualenvs]
in-project = true
這樣能夠保證,在使用poetry安裝依賴文件時自動創建虛擬環境。
然后使用的時候執行下面命令激活虛擬環境
source .venv/bin/activate
4.4 其他命令
update
獲取所有依賴項的最新版本並更新 poetry.lock 文件
poetry update
指定依賴項進行更新
poetry update requests toml
options
--dry-run :輸出操作,但不執行操作
--no-dev : 不安裝開發依賴項
--lock:不執行安裝,僅更新 poetry.lock 文件
add
將所需要的包添加到 pyproject.toml 的 [tool.poetry.dependencies] 下面,並安裝他們
未指定版本的話,則 poetry 會自動選擇合適的版本
poetry add requests pendulum
注意
默認不會將包添加到 [tool.poetry.dev-dependencies] 下,若需要得用 --dev 參數
指定版本
poetry add pendulum@^2.0.5
poetry add "pendulum>=2.0.5"
獲取最新的版本
poetry add pendulum@latest
添加 github 依賴項
poetry add git+https://github.com/sdispater/pendulum.git
添加 github 依賴項,指定分支
poetry add git+https://github.com/sdispater/pendulum.git#develop
poetry add git+https://github.com/sdispater/pendulum.git#2.0.5
通過本地目錄、文件進行安裝
poetry add ./my-package/
poetry add ../my-package/dist/my-package-0.1.0.tar.gz
poetry add ../my-package/dist/my_package-0.1.0.whl
以可編輯模式安裝依賴項
在 pyproject.toml 文件指定,意味着本地目錄中的更改會直接反映在環境中
[tool.poetry.dependencies]
my-package = {path = "../my/path", develop = true}
options
--dev (-D):將包添加為開發依賴項
--path:指定依賴項的路徑
--optional:作為可選依賴項添加
--dry-run:輸出操作,不執行任何操作
--lock:不執行安裝,僅更新 poetry.lock 文件
remove
從已安裝包列表刪除指定包
poetry remove pendulum
options
--dev(-D):從開發依賴項中刪除包
--dry-run:輸出操作,不執行任何操作
show
根據 poetry.lock 列出所有可用的軟件包,並不是根據 pyproject.toml 文件的 [tool.poetry.dependencies]
poetry show
查看某個包的詳細信息
poetry show fastapi
options
--no-dev:不要列出開發依賴項
--tree:樹的形式列出依賴項
--latest (-l):顯示最新版本
--outdated (-o):顯示最新版本,但僅適用於過時的軟件包
run
在項目的 virtualenv 中執行指定的命令
poetry run python -V
還可以執行 pyproject.toml 中定義的腳本
[tool.poetry.scripts]
my_script = "my_module:main"
執行 shell
poetry run my_script
顯式激活當前虛擬環境,會自動調用虛擬環境下的激活命令
如果不存在虛擬環境,會自動創建一個
check
驗證 pyproject.toml 文件的結構,並在出現任何錯誤時返回詳細報告
poetry check
search
在遠程庫上搜索包
poetry search requests
lock
將所有依賴項鎖定為最新的可用兼容版本
poetry lock
version
顯示項目的當前版本
是 pyproject.toml 文件的 version 哦
export
將鎖文件導出為其他格式
poetry export -f requirements.txt --output requirements.txt
options
--format (-f):要導出的格式(默認值:requirements.txt)目前,僅支持requirements.txt
--output (-o):輸出文件的名稱,如果省略,則打印到標准輸出
--dev(-D):從開發依賴項中刪除包
--extras (-E):要包含的額外依賴項集
--without-hashes:從導出的文件中排除散列
--with-credentials:包括用於額外索引的憑據
env
管理虛擬環境,具體教程看:https://www.cnblogs.com/poloyy/p/15270670.html
cache
build
生成源文件
poetry build
publish
將使用 build 命令生成的包發布到遠程存儲庫
poetry publish
options
--repository (-r):要將包注冊到的存儲庫(默認值:pypi)應與config命令設置的存儲庫名稱匹配
--username (-u):訪問存儲庫的用戶名
--password (-p):訪問存儲庫的密碼
--dry-run:執行除上傳包以外的所有操作
5 使用過程中遇到的問題
5.1 依賴源的問題
添加依賴的命令
poetry add <pakge_name>
但是有些不好用
poetry add fastapi[all]
Using version ^0.63.0 for fastapi
Updating dependencies
Resolving dependencies...
ConnectionError
HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Max retries exceeded with url: /packages/f4/2b/078a9771ae4b67e36b0c2a973df845260833a4eb088b81c84b738509b4c4/aiofiles-0.5.0-py3-none-any.whl (Caused by NewConnectionError('
<urllib3.connection.HTTPSConnection object at 0x0000021BE6355250>: Failed to establish a new connection: [WinError 10060] 由於連接方在一段時間后沒有正確答復或連接的主機沒有反應,連接嘗試失敗。'))
at c:\users\admin\.local\pipx\venvs\poetry\lib\site-packages\requests\adapters.py:516 in send
512│ if isinstance(e.reason, _SSLError):
513│ # This branch is for urllib3 v1.22 and later.
514│ raise SSLError(e, request=request)
515│
→ 516│ raise ConnectionError(e, request=request)
517│
518│ except ClosedPoolError as e:
519│ raise ConnectionError(e, request=request)
520│
從錯誤提示來看,從其他源下載文件,所以出現了網絡錯誤。
這是poetry已經被吐槽很多次的問題了。。。
解決辦法:
pyproject.toml 文件中添加清華鏡像或者阿里雲鏡像:
[[tool.poetry.source]]
name = "aliyun"
url = "https://mirrors.aliyun.com/pypi/simple"
# name = "tsinghua"
# url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/"
但是這不能夠完全保證,依然會遇到一些問題
[[tool.poetry.source]] 僅對部分環節有效, 在某些步驟 (如 resolve dependencies...) poetry 仍然使用的是 pypi url,
而我們國內訪問不了或者連接超時, 就引起了報錯.
解決方法:
加一個 default 參數:
[[tool.poetry.source]]
name = "tsinghua"
url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/"
default = true # 添加一個 default 參數, 使 poetry 的默認回調行為都調用到這個清華鏡像上.
參考:
https://github.com/python-poetry/poetry/issues/559
https://python-poetry.org/docs/repositories/#disabling-the-pypi-repository
5.2 添加開發依賴
默認情況下,poetry所添加的依賴是在運行這個項目時所需要的一些包,但是在我們開發的時候,其實還需要一些工具進行配合。
比如說測試框架pytest,如果單純是為了啟動這個項目的話,其實是不需要進行安裝的。
所以把這些在運行時不需要安裝,在開發時所需要安裝的依賴我們稱之為開發依賴。
安裝開發依賴的方式很簡單,就是加一個-D參數
poetry add -D pytest
Using version ^6.2.2 for pytest
Updating dependencies
Resolving dependencies...
Writing lock file
Package operations: 9 installs, 0 updates, 0 removals
• Installing pyparsing (2.4.7)
• Installing atomicwrites (1.4.0)
• Installing attrs (20.3.0)
• Installing iniconfig (1.1.1)
• Installing packaging (20.9)
• Installing py (1.10.0)
• Installing pluggy (0.13.1)
• Installing toml (0.10.2)
• Installing pytest (6.2.2)
然后我們運行pytest執行測試。
有兩種方式來驗證:
第一種:先進入虛擬環境,然后執行pytest
poetry shell
pytest
第二種:讓pytest在虛擬環境中執行
poetry run pytest
=============== 29 passed in 1.13s ===============
5.3 什么時候使用 ‘poetry.lock’, 什么時候不使用?
多數人以及要發布模塊到 pypi 的人不需要 poetry.lock; 通過 Version Control 進行協作的開發團隊以及對他機部署環境要求非常嚴格的人則需要放入 poetry.lock.
poetry.lock 的意義在於, 它會徹底 “鎖死” 項目依賴的版本,
比如我們在 pyproject.toml 中要求的依賴版本是 requests = "^2.24.0",
那么哪怕 requests 的作者后面發布了 2.24.1, 使用 poetry.lock 安裝時仍會選擇安裝 2.24.0 版本.
因此, poetry.lock 幫助我們徹底杜絕因依賴的版本的微小變化而產生的任何不確定性.
補充說明:
如需使用 poetry.lock, 請將它伴隨項目一起打包發布, 在執行 poetry install 時它會優先查找 lock 文件.
你可以通過 poetry update 來更新所有依賴到最新版本, 同時 poetry.lock 也會鎖定到新的依賴版本.
當pyproject.toml 中所列的依賴與 poetry.lock 不匹配時, poetry install 會中斷並提示該錯誤.
5.4 為項目添加執行入口
我們可以將項目啟動的命令,或者啟動入口寫為腳本,然后加入到配置文件中,然后文件執行 poetry install 操作時,就會將項目編譯為可執行文件了
[tool.poetry.scripts]
package-transformer = "newapi.test:main"
這里注意格式, “ package-transformer”是編譯生成的可執行目標文件,方便以后運行使用
"newapi.test:main" 是程序執行的如可文件和函數名
6 例子和總結
現在新的項目已經使用poetry和pyproject.toml來進行管理了。
poetry new newtest --name newapi
[tool.poetry]
name = "newapi"
version = "0.1.0"
description = ""
authors = ["Dummy"]
[tool.poetry.dependencies]
python = "^3.8"
[tool.poetry.dev-dependencies]
pytest = "^5.2"
# 程序執行入口
[tool.poetry.scripts]
test-package = "newapi.main:main"
# 添加清華源,防止構建依賴時因為網絡問題不能構建成功
[[tool.poetry.source]]
name = "tsinghua"
url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/"
default = true # 添加一個 default 參數, 使 poetry 的默認回調行為都調用到
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
main文件:
import time
import os
def test():
print('hello word')
print(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()))
def main(**kwargs):
"""Entry point """
test()
print(os.getcwd())
time.sleep(10)
print('test end after 10s')
if __name__ == "__main__":
main()
現在項目結構如下:‘
newtest
├── pyproject.toml # poetry 用於管理項目的 all-in-one 配置文檔.
├── README.rst # 說明文檔
├── newapi # poetry 會幫你將包名調整為下划線格式.
│ ├──__init__.py # 請在該目錄下編寫你的業務邏輯.
│ └── main.py
└── tests # 測試模塊.
├── __init__.py
└── test_my_package.py
夠構建環境`
poetry install
激活虛擬環境
source .venv/Script/activate
根據構建的程序入口運行程序
test-package
回顧發現,poetry在開始做了幾件件事:
初始化pyproject.toml
構建主程序入口
修改配置文件,增加程序入口和修改鏡像源
創建虛擬環境
構建下載相關依賴
根據配置信息生成可執行入口
之后,主要負責:
管理依賴