Python 課程 ── 封裝與發佈(Packaging & Distribution)
主題:Poetry 與 Flit
簡介
在 Python 生態系統中,封裝(Packaging)與發佈(Distribution)是把程式碼分享給其他開發者或部署到生產環境的關鍵步驟。傳統上,我們會使用 setup.py、requirements.txt 等檔案,但隨著專案規模與依賴管理需求的提升,Poetry 與 Flit 兩個工具因其簡潔、可預測的工作流程而受到廣大開發者的青睞。
- Poetry:提供完整的依賴解析、虛擬環境管理與發佈功能,讓
pyproject.toml成為唯一需要維護的設定檔。 - Flit:主打「最小化」的封裝流程,適合單檔或小型套件,僅需要一個
pyproject.toml即可完成打包與上傳。
本篇文章將帶你快速掌握兩者的核心概念、實作範例,以及在真實專案中如何選擇與避免常見陷阱。
核心概念
1. 為什麼使用 pyproject.toml?
PEP 518 定義了 pyproject.toml 作為 建置系統 的統一入口。它取代了過去散落在 setup.py、setup.cfg、MANIFEST.in 等檔案的設定,使得:
- 工具獨立:同一個檔案可以被 Poetry、Flit、Black、isort 等工具共用。
- 可重現環境:所有依賴(包括建置依賴)都寫在同一個地方,CI/CD 更加可靠。
重點:在使用 Poetry 或 Flit 前,先確定專案根目錄下已存在
pyproject.toml,且內容符合對應工具的規範。
2. Poetry 的工作流程
- 初始化專案:
poetry new my_pkg會產生完整的目錄結構與pyproject.toml。 - 依賴管理:
poetry add requests自動解析相容版本,並寫入tool.poetry.dependencies。 - 虛擬環境:Poetry 內建環境管理,
poetry shell直接切換到專屬的 venv。 - 打包與發佈:
poetry build產生.whl與.tar.gz,poetry publish直接推送至 PyPI。
範例:使用 Poetry 建立與發佈簡易套件
# 1. 建立新專案
poetry new hello_world
cd hello_world
# 2. 新增執行時依賴
poetry add click
# 3. 編寫程式碼 (src/hello_world/__init__.py)
# 這裡示範使用 click 建立 CLI
# src/hello_world/__init__.py
import click
@click.command()
@click.argument("name", default="World")
def main(name: str) -> None:
"""簡單的問候程式,輸入姓名即可得到問候語。"""
click.echo(f"Hello, {name}!")
# pyproject.toml 片段
[tool.poetry.scripts]
hello = "hello_world:main"
# 4. 建置套件
poetry build
# 5. 發佈到測試 PyPI(先在 https://test.pypi.org 註冊帳號)
poetry config repositories.test-pypi https://test.pypi.org/legacy/
poetry publish -r test-pypi
完成後,任何使用者只要執行
pip install -i https://test.pypi.org/simple/ hello-world,即可在命令列呼叫hello。
3. Flit 的工作流程
Flit 的理念是「只要有 pyproject.toml,就能打包」。它不管理虛擬環境,也不提供依賴解析功能,適合:
- 單檔或少量模組的套件。
- 想要快速上傳至 PyPI,且不需要複雜的依賴約束。
範例:使用 Flit 打包與上傳
# 1. 安裝 Flit
pip install flit
# 2. 建立目錄與程式碼
mkdir myutils
touch myutils/__init__.py
# myutils/__init__.py
def add(a: int, b: int) -> int:
"""回傳兩個整數的加總。"""
return a + b
# pyproject.toml(放在專案根目錄)
[build-system]
requires = ["flit_core >=3.2,<4"]
build-backend = "flit_core.buildapi"
[project]
name = "myutils"
version = "0.1.0"
description = "A tiny utility library for demonstration."
authors = [{name = "Your Name", email = "you@example.com"}]
requires-python = ">=3.8"
dependencies = [] # 若有外部依賴,直接列在此
# 3. 檢查與建置
flit build
# 4. 發佈到正式 PyPI(首次需要先設定 API token)
flit publish
注意:Flit 只會把
myutils包含的 Python 檔案與pyproject.toml中宣告的資料一起打包;若需要額外的非程式碼檔案(如 README、LICENSE),必須在project區段的readme、license欄位中說明。
4. 依賴與版本管理的差異
| 功能 | Poetry | Flit |
|---|---|---|
| 依賴解析(解決衝突) | ✅ 內建解決衝突與鎖檔 poetry.lock |
❌ 需自行管理 requirements.txt 或手動指定 |
| 虛擬環境管理 | ✅ 自動建立、切換 | ❌ 不提供 |
| 多平台建置(wheel) | ✅ 支援 poetry build |
✅ 支援 flit build |
| 發佈流程 | ✅ 一鍵 publish |
✅ 一鍵 publish |
| 輕量化 | 中等(功能較多) | 輕量(僅打包) |
常見陷阱與最佳實踐
1. 依賴衝突未被偵測
Poetry:若直接編輯
pyproject.toml而未使用poetry add,Poetry 可能不會重新產生poetry.lock,導致環境與鎖檔不一致。
解法:每次手動修改依賴後執行poetry lock --no-update或poetry install。Flit:沒有鎖檔機制,若依賴版本寫成
requests>=2.0,不同環境安裝的實際版本可能不同。
解法:在dependencies中使用固定版本或~=,==,或額外維護requirements.txt。
2. 打包時遺漏檔案
- 確保
include/exclude設定正確。 - 在 Poetry 中使用
packages = [{ include = "my_pkg", from = "src" }];在 Flit 中使用module = "myutils"或packages = ["myutils"]。
3. 發佈到錯誤的 PyPI
- Poetry 會保留多個 repository 設定,容易把測試套件推到正式 PyPI。
最佳實踐:在 CI 中明確設定--repository test-pypi;發佈前使用poetry config pypi-token.pypi <TOKEN>只授權正式 PyPI。
4. Python 版本相容性
- 在
pyproject.toml中明確宣告requires-python = ">=3.8,<4",避免使用者在不支援的 Python 版本安裝失敗。
5. 輸入錯誤的套件名稱
- PyPI 套件名稱不可包含大寫、特殊符號。
- Poetry/Flit 都會在
publish前檢查名稱是否合法,但仍建議先在本地執行poetry check或flit check。
實際應用場景
| 場景 | 建議工具 | 為什麼 |
|---|---|---|
| 公司內部共享工具庫(多模組、需固定依賴) | Poetry | 鎖檔與虛擬環境保證所有開發者使用相同套件版本。 |
單檔 CLI 小工具(如 csv2json) |
Flit | 輕量、只需 pyproject.toml,快速上傳即可。 |
開源套件(希望提供 sdist 與 wheel) |
Poetry 或 Flit(視套件大小) | 兩者皆支援 twine 兼容的檔案格式;Poetry 更適合有複雜依賴的情況。 |
| CI/CD 自動化發佈 | Poetry(配合 GitHub Actions) | poetry publish --build 可在 CI 中一次完成建置與上傳。 |
| 需要自訂建置步驟(C 擴充套件) | Poetry(可透過 build-system 加入 setuptools-rust) |
Poetry 允許在 pyproject.toml 中混合多種建置後端。 |
總結
- Poetry 與 Flit 都是以
pyproject.toml為核心的現代化封裝工具,選擇哪一個取決於專案的規模與需求。 - Poetry 提供完整的依賴解析、虛擬環境與鎖檔管理,適合中大型套件或需要嚴格環境一致性的團隊。
- Flit 則以「最小化」為目標,適合單檔或小型工具,快速完成打包與上傳。
- 無論使用哪個工具,都應遵守 版本宣告、檔案包含、測試發佈 等最佳實踐,才能讓套件在 PyPI 上保持高品質與可維護性。
掌握了 Poetry 與 Flit 的使用方式,你就能把自己的程式碼從本機開發環境,順利、可靠地分享給全球的 Python 使用者。祝你封裝順利、發佈成功! 🚀