<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>案例研究 on Tarragon</title><link>https://tarrragon.github.io/blog/python-advanced/07-packaging/case-studies/</link><description>Recent content in 案例研究 on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Wed, 21 Jan 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/python-advanced/07-packaging/case-studies/index.xml" rel="self" type="application/rss+xml"/><item><title>案例：打包共用庫</title><link>https://tarrragon.github.io/blog/python-advanced/07-packaging/case-studies/package-library/</link><pubDate>Wed, 21 Jan 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/python-advanced/07-packaging/case-studies/package-library/</guid><description>&lt;p>本案例基於 &lt;code>.claude/lib&lt;/code> 整體結構，展示如何將內部共用庫打包成可重用的 Python 套件。&lt;/p>
&lt;h2 id="先備知識">先備知識&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/python-advanced/07-packaging/" data-link-title="模組七：打包與發布" data-link-desc="學習現代 Python 套件的打包與發布流程">模組六：打包與發布&lt;/a>&lt;/li>
&lt;li>Python 模組與套件基礎&lt;/li>
&lt;/ul>
&lt;h2 id="問題背景">問題背景&lt;/h2>
&lt;h3 id="現有設計">現有設計&lt;/h3>
&lt;p>&lt;code>.claude/lib&lt;/code> 目錄結構：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">.claude/lib/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">├── __init__.py # Package entry point with version
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">├── config_loader.py # YAML/JSON configuration loader
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">├── git_utils.py # Git operations (branch, worktree)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">├── hook_io.py # Hook I/O standardization
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">├── hook_logging.py # Logging system for hooks
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">├── hook_validator.py # Hook compliance validator
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">├── markdown_link_checker.py # Markdown link validation
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">├── README.md # API documentation
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">└── tests/ # Unit tests
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> ├── __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl"> ├── test_config_loader.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl"> ├── test_git_utils.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl"> ├── test_hook_io.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl"> └── test_hook_logging.py&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>這是一個典型的內部工具庫，包含四個核心模組：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>模組&lt;/th>
 &lt;th>功能&lt;/th>
 &lt;th>相依性&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;code>config_loader&lt;/code>&lt;/td>
 &lt;td>YAML/JSON 配置載入&lt;/td>
 &lt;td>PyYAML (optional)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>git_utils&lt;/code>&lt;/td>
 &lt;td>Git 命令執行與分支管理&lt;/td>
 &lt;td>無（使用 subprocess）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>hook_io&lt;/code>&lt;/td>
 &lt;td>Hook 輸入輸出標準化&lt;/td>
 &lt;td>無（使用標準庫）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>hook_logging&lt;/code>&lt;/td>
 &lt;td>日誌系統設定&lt;/td>
 &lt;td>無（使用標準庫）&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="現有限制">現有限制&lt;/h3>
&lt;p>作為內部目錄的問題：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>無法跨專案重用&lt;/strong>：程式碼被鎖定在單一專案中&lt;/li>
&lt;li>&lt;strong>沒有版本管理&lt;/strong>：無法追蹤 API 變更&lt;/li>
&lt;li>&lt;strong>無法透過 pip 安裝&lt;/strong>：其他專案必須複製程式碼&lt;/li>
&lt;li>&lt;strong>相依性管理不明確&lt;/strong>：PyYAML 是可選還是必要？&lt;/li>
&lt;/ul>
&lt;h2 id="進階解決方案">進階解決方案&lt;/h2>
&lt;h3 id="設計目標">設計目標&lt;/h3>
&lt;ol>
&lt;li>&lt;strong>建立標準的 Python 套件結構&lt;/strong>&lt;/li>
&lt;li>&lt;strong>使用 pyproject.toml 管理元資料&lt;/strong>&lt;/li>
&lt;li>&lt;strong>支援 pip install&lt;/strong>&lt;/li>
&lt;li>&lt;strong>建立 CI/CD 發布流程&lt;/strong>&lt;/li>
&lt;/ol>
&lt;h3 id="實作步驟">實作步驟&lt;/h3>
&lt;h4 id="步驟-1重組目錄結構">步驟 1：重組目錄結構&lt;/h4>
&lt;p>從內部目錄結構轉換為標準的 &lt;strong>src layout&lt;/strong>：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">claude-hooks-lib/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">├── pyproject.toml # Package metadata and build config
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">├── README.md # Package documentation
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">├── LICENSE # License file (MIT recommended)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">├── CHANGELOG.md # Version history
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">├── src/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">│ └── claude_hooks_lib/ # Package directory (underscore for import)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">│ ├── __init__.py # Public API exports
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">│ ├── config_loader.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">│ ├── git_utils.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">│ ├── hook_io.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">│ ├── hook_logging.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">│ ├── hook_validator.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">│ └── py.typed # PEP 561 marker for type hints
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">└── tests/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl"> ├── __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl"> ├── conftest.py # Pytest fixtures
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl"> ├── test_config_loader.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl"> ├── test_git_utils.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl"> ├── test_hook_io.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl"> └── test_hook_logging.py&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="為什麼選擇-src-layout">為什麼選擇 src layout？&lt;/h5>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl"># Flat layout (不推薦用於套件發布)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">my-package/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">├── my_package/ # Package 直接在根目錄
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">│ └── __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">└── tests/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl"># Src layout (推薦)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">my-package/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">├── src/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">│ └── my_package/ # Package 在 src/ 下
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">│ └── __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">└── tests/&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>特性&lt;/th>
 &lt;th>Flat Layout&lt;/th>
 &lt;th>Src Layout&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>測試環境&lt;/td>
 &lt;td>可能意外導入本地版本&lt;/td>
 &lt;td>強制安裝後測試&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>套件發布&lt;/td>
 &lt;td>容易遺漏檔案&lt;/td>
 &lt;td>明確的套件邊界&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>複雜度&lt;/td>
 &lt;td>較低&lt;/td>
 &lt;td>稍高&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>推薦場景&lt;/td>
 &lt;td>簡單專案、應用程式&lt;/td>
 &lt;td>套件發布、函式庫&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h4 id="步驟-2建立-pyprojecttoml">步驟 2：建立 pyproject.toml&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">build-system&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="nx">requires&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;hatchling&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">build-backend&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;hatchling.build&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;claude-hooks-lib&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;0.28.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">description&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Shared utilities for Claude Code hooks&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="nx">readme&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;README.md&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="nx">license&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;MIT&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nx">requires-python&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;gt;=3.10&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="nx">authors&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl"> &lt;span class="p">{&lt;/span> &lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Your Name&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">email&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;your.email@example.com&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="nx">keywords&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;claude&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;hooks&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;utilities&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;git&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="nx">classifiers&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Development Status :: 4 - Beta&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Intended Audience :: Developers&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;License :: OSI Approved :: MIT License&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Operating System :: OS Independent&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: 3&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: 3.10&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: 3.11&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: 3.12&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: 3.13&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Typing :: Typed&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl">&lt;span class="c"># Core dependencies (minimal)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl">&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">optional-dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl">&lt;span class="c"># YAML support&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">34&lt;/span>&lt;span class="cl">&lt;span class="nx">yaml&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;PyYAML&amp;gt;=6.0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">35&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">36&lt;/span>&lt;span class="cl">&lt;span class="c"># Development dependencies&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">37&lt;/span>&lt;span class="cl">&lt;span class="nx">dev&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">38&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;pytest&amp;gt;=8.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">39&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;pytest-cov&amp;gt;=4.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">40&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;mypy&amp;gt;=1.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">41&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;ruff&amp;gt;=0.4&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">42&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">43&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">44&lt;/span>&lt;span class="cl">&lt;span class="c"># All optional features&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">45&lt;/span>&lt;span class="cl">&lt;span class="nx">all&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;claude-hooks-lib[yaml]&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">46&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">47&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">urls&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">48&lt;/span>&lt;span class="cl">&lt;span class="nx">Homepage&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://github.com/yourname/claude-hooks-lib&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">49&lt;/span>&lt;span class="cl">&lt;span class="nx">Documentation&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://github.com/yourname/claude-hooks-lib#readme&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">50&lt;/span>&lt;span class="cl">&lt;span class="nx">Repository&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://github.com/yourname/claude-hooks-lib.git&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">51&lt;/span>&lt;span class="cl">&lt;span class="nx">Changelog&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://github.com/yourname/claude-hooks-lib/blob/main/CHANGELOG.md&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">52&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">53&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">scripts&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">54&lt;/span>&lt;span class="cl">&lt;span class="c"># Command-line entry points&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">55&lt;/span>&lt;span class="cl">&lt;span class="nx">hook-validator&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;claude_hooks_lib.hook_validator:main&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">56&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">57&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">targets&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">sdist&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">58&lt;/span>&lt;span class="cl">&lt;span class="nx">include&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">59&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;/src&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">60&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;/tests&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">61&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">62&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">63&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">targets&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">wheel&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">64&lt;/span>&lt;span class="cl">&lt;span class="nx">packages&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;src/claude_hooks_lib&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="關鍵設定說明">關鍵設定說明&lt;/h5>
&lt;ol>
&lt;li>&lt;strong>build-system&lt;/strong>：使用 Hatch 作為建構後端（現代、快速）&lt;/li>
&lt;li>&lt;strong>requires-python&lt;/strong>：指定最低 Python 版本&lt;/li>
&lt;li>&lt;strong>dependencies&lt;/strong>：核心相依性保持為空（僅使用標準庫）&lt;/li>
&lt;li>&lt;strong>optional-dependencies&lt;/strong>：將 PyYAML 設為可選&lt;/li>
&lt;li>&lt;strong>project.scripts&lt;/strong>：定義命令列工具入口點&lt;/li>
&lt;/ol>
&lt;h4 id="步驟-3處理相依性">步驟 3：處理相依性&lt;/h4>
&lt;p>相依性分層策略：&lt;/p></description><content:encoded><![CDATA[<p>本案例基於 <code>.claude/lib</code> 整體結構，展示如何將內部共用庫打包成可重用的 Python 套件。</p>
<h2 id="先備知識">先備知識</h2>
<ul>
<li><a href="/blog/python-advanced/07-packaging/" data-link-title="模組七：打包與發布" data-link-desc="學習現代 Python 套件的打包與發布流程">模組六：打包與發布</a></li>
<li>Python 模組與套件基礎</li>
</ul>
<h2 id="問題背景">問題背景</h2>
<h3 id="現有設計">現有設計</h3>
<p><code>.claude/lib</code> 目錄結構：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">.claude/lib/
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── __init__.py              # Package entry point with version
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">├── config_loader.py         # YAML/JSON configuration loader
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">├── git_utils.py             # Git operations (branch, worktree)
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">├── hook_io.py               # Hook I/O standardization
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">├── hook_logging.py          # Logging system for hooks
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">├── hook_validator.py        # Hook compliance validator
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">├── markdown_link_checker.py # Markdown link validation
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">├── README.md                # API documentation
</span></span><span class="line"><span class="ln">10</span><span class="cl">└── tests/                   # Unit tests
</span></span><span class="line"><span class="ln">11</span><span class="cl">    ├── __init__.py
</span></span><span class="line"><span class="ln">12</span><span class="cl">    ├── test_config_loader.py
</span></span><span class="line"><span class="ln">13</span><span class="cl">    ├── test_git_utils.py
</span></span><span class="line"><span class="ln">14</span><span class="cl">    ├── test_hook_io.py
</span></span><span class="line"><span class="ln">15</span><span class="cl">    └── test_hook_logging.py</span></span></code></pre></div><p>這是一個典型的內部工具庫，包含四個核心模組：</p>
<table>
  <thead>
      <tr>
          <th>模組</th>
          <th>功能</th>
          <th>相依性</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>config_loader</code></td>
          <td>YAML/JSON 配置載入</td>
          <td>PyYAML (optional)</td>
      </tr>
      <tr>
          <td><code>git_utils</code></td>
          <td>Git 命令執行與分支管理</td>
          <td>無（使用 subprocess）</td>
      </tr>
      <tr>
          <td><code>hook_io</code></td>
          <td>Hook 輸入輸出標準化</td>
          <td>無（使用標準庫）</td>
      </tr>
      <tr>
          <td><code>hook_logging</code></td>
          <td>日誌系統設定</td>
          <td>無（使用標準庫）</td>
      </tr>
  </tbody>
</table>
<h3 id="現有限制">現有限制</h3>
<p>作為內部目錄的問題：</p>
<ul>
<li><strong>無法跨專案重用</strong>：程式碼被鎖定在單一專案中</li>
<li><strong>沒有版本管理</strong>：無法追蹤 API 變更</li>
<li><strong>無法透過 pip 安裝</strong>：其他專案必須複製程式碼</li>
<li><strong>相依性管理不明確</strong>：PyYAML 是可選還是必要？</li>
</ul>
<h2 id="進階解決方案">進階解決方案</h2>
<h3 id="設計目標">設計目標</h3>
<ol>
<li><strong>建立標準的 Python 套件結構</strong></li>
<li><strong>使用 pyproject.toml 管理元資料</strong></li>
<li><strong>支援 pip install</strong></li>
<li><strong>建立 CI/CD 發布流程</strong></li>
</ol>
<h3 id="實作步驟">實作步驟</h3>
<h4 id="步驟-1重組目錄結構">步驟 1：重組目錄結構</h4>
<p>從內部目錄結構轉換為標準的 <strong>src layout</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">claude-hooks-lib/
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── pyproject.toml           # Package metadata and build config
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">├── README.md                # Package documentation
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">├── LICENSE                  # License file (MIT recommended)
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">├── CHANGELOG.md             # Version history
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">├── src/
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">│   └── claude_hooks_lib/    # Package directory (underscore for import)
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">│       ├── __init__.py      # Public API exports
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">│       ├── config_loader.py
</span></span><span class="line"><span class="ln">10</span><span class="cl">│       ├── git_utils.py
</span></span><span class="line"><span class="ln">11</span><span class="cl">│       ├── hook_io.py
</span></span><span class="line"><span class="ln">12</span><span class="cl">│       ├── hook_logging.py
</span></span><span class="line"><span class="ln">13</span><span class="cl">│       ├── hook_validator.py
</span></span><span class="line"><span class="ln">14</span><span class="cl">│       └── py.typed         # PEP 561 marker for type hints
</span></span><span class="line"><span class="ln">15</span><span class="cl">└── tests/
</span></span><span class="line"><span class="ln">16</span><span class="cl">    ├── __init__.py
</span></span><span class="line"><span class="ln">17</span><span class="cl">    ├── conftest.py          # Pytest fixtures
</span></span><span class="line"><span class="ln">18</span><span class="cl">    ├── test_config_loader.py
</span></span><span class="line"><span class="ln">19</span><span class="cl">    ├── test_git_utils.py
</span></span><span class="line"><span class="ln">20</span><span class="cl">    ├── test_hook_io.py
</span></span><span class="line"><span class="ln">21</span><span class="cl">    └── test_hook_logging.py</span></span></code></pre></div><h5 id="為什麼選擇-src-layout">為什麼選擇 src layout？</h5>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl"># Flat layout (不推薦用於套件發布)
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">my-package/
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">├── my_package/          # Package 直接在根目錄
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">│   └── __init__.py
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">└── tests/
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"># Src layout (推薦)
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">my-package/
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">├── src/
</span></span><span class="line"><span class="ln">10</span><span class="cl">│   └── my_package/      # Package 在 src/ 下
</span></span><span class="line"><span class="ln">11</span><span class="cl">│       └── __init__.py
</span></span><span class="line"><span class="ln">12</span><span class="cl">└── tests/</span></span></code></pre></div><table>
  <thead>
      <tr>
          <th>特性</th>
          <th>Flat Layout</th>
          <th>Src Layout</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>測試環境</td>
          <td>可能意外導入本地版本</td>
          <td>強制安裝後測試</td>
      </tr>
      <tr>
          <td>套件發布</td>
          <td>容易遺漏檔案</td>
          <td>明確的套件邊界</td>
      </tr>
      <tr>
          <td>複雜度</td>
          <td>較低</td>
          <td>稍高</td>
      </tr>
      <tr>
          <td>推薦場景</td>
          <td>簡單專案、應用程式</td>
          <td>套件發布、函式庫</td>
      </tr>
  </tbody>
</table>
<h4 id="步驟-2建立-pyprojecttoml">步驟 2：建立 pyproject.toml</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">build-system</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nx">requires</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;hatchling&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">build-backend</span> <span class="p">=</span> <span class="s2">&#34;hatchling.build&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;claude-hooks-lib&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.28.0&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">description</span> <span class="p">=</span> <span class="s2">&#34;Shared utilities for Claude Code hooks&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nx">readme</span> <span class="p">=</span> <span class="s2">&#34;README.md&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nx">license</span> <span class="p">=</span> <span class="s2">&#34;MIT&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">requires-python</span> <span class="p">=</span> <span class="s2">&#34;&gt;=3.10&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nx">authors</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="p">{</span> <span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;Your Name&#34;</span><span class="p">,</span> <span class="nx">email</span> <span class="p">=</span> <span class="s2">&#34;your.email@example.com&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="nx">keywords</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;claude&#34;</span><span class="p">,</span> <span class="s2">&#34;hooks&#34;</span><span class="p">,</span> <span class="s2">&#34;utilities&#34;</span><span class="p">,</span> <span class="s2">&#34;git&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="nx">classifiers</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="s2">&#34;Development Status :: 4 - Beta&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="s2">&#34;Intended Audience :: Developers&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="s2">&#34;License :: OSI Approved :: MIT License&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="s2">&#34;Operating System :: OS Independent&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: 3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: 3.10&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: 3.11&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: 3.12&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: 3.13&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">    <span class="s2">&#34;Typing :: Typed&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="c"># Core dependencies (minimal)</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">optional-dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="c"># YAML support</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="nx">yaml</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;PyYAML&gt;=6.0&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">
</span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="c"># Development dependencies</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="nx">dev</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">    <span class="s2">&#34;pytest&gt;=8.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl">    <span class="s2">&#34;pytest-cov&gt;=4.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl">    <span class="s2">&#34;mypy&gt;=1.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">    <span class="s2">&#34;ruff&gt;=0.4&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">43</span><span class="cl">
</span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="c"># All optional features</span>
</span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="nx">all</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;claude-hooks-lib[yaml]&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">46</span><span class="cl">
</span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">urls</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="nx">Homepage</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/yourname/claude-hooks-lib&#34;</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="nx">Documentation</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/yourname/claude-hooks-lib#readme&#34;</span>
</span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="nx">Repository</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/yourname/claude-hooks-lib.git&#34;</span>
</span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="nx">Changelog</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/yourname/claude-hooks-lib/blob/main/CHANGELOG.md&#34;</span>
</span></span><span class="line"><span class="ln">52</span><span class="cl">
</span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">scripts</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">54</span><span class="cl"><span class="c"># Command-line entry points</span>
</span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="nx">hook-validator</span> <span class="p">=</span> <span class="s2">&#34;claude_hooks_lib.hook_validator:main&#34;</span>
</span></span><span class="line"><span class="ln">56</span><span class="cl">
</span></span><span class="line"><span class="ln">57</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">build</span><span class="p">.</span><span class="nx">targets</span><span class="p">.</span><span class="nx">sdist</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">58</span><span class="cl"><span class="nx">include</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">59</span><span class="cl">    <span class="s2">&#34;/src&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">60</span><span class="cl">    <span class="s2">&#34;/tests&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">61</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">62</span><span class="cl">
</span></span><span class="line"><span class="ln">63</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">build</span><span class="p">.</span><span class="nx">targets</span><span class="p">.</span><span class="nx">wheel</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">64</span><span class="cl"><span class="nx">packages</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;src/claude_hooks_lib&#34;</span><span class="p">]</span></span></span></code></pre></div><h5 id="關鍵設定說明">關鍵設定說明</h5>
<ol>
<li><strong>build-system</strong>：使用 Hatch 作為建構後端（現代、快速）</li>
<li><strong>requires-python</strong>：指定最低 Python 版本</li>
<li><strong>dependencies</strong>：核心相依性保持為空（僅使用標準庫）</li>
<li><strong>optional-dependencies</strong>：將 PyYAML 設為可選</li>
<li><strong>project.scripts</strong>：定義命令列工具入口點</li>
</ol>
<h4 id="步驟-3處理相依性">步驟 3：處理相依性</h4>
<p>相依性分層策略：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c"># 核心相依性：僅標準庫</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">optional-dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c"># 功能性相依性（用戶根據需求安裝）</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">yaml</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;PyYAML&gt;=6.0&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c"># 開發相依性（僅開發者需要）</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nx">dev</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="s2">&#34;pytest&gt;=8.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="s2">&#34;pytest-cov&gt;=4.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="s2">&#34;mypy&gt;=1.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="s2">&#34;ruff&gt;=0.4&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="c"># 測試相依性（CI/CD 需要）</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="nx">test</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="s2">&#34;pytest&gt;=8.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="s2">&#34;pytest-cov&gt;=4.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="c"># 文件相依性</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="nx">docs</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="s2">&#34;mkdocs&gt;=1.5&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">    <span class="s2">&#34;mkdocs-material&gt;=9.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="c"># 完整安裝</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="nx">all</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">    <span class="s2">&#34;claude-hooks-lib[yaml,dev,docs]&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="p">]</span></span></span></code></pre></div><h5 id="安裝方式範例">安裝方式範例</h5>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 基本安裝（無可選相依性）</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">pip install claude-hooks-lib
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 包含 YAML 支援</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">pip install <span class="s2">&#34;claude-hooks-lib[yaml]&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># 開發者安裝</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">pip install -e <span class="s2">&#34;.[dev]&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># 完整安裝</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">pip install <span class="s2">&#34;claude-hooks-lib[all]&#34;</span></span></span></code></pre></div><h4 id="步驟-4版本管理策略">步驟 4：版本管理策略</h4>
<h5 id="方法-a單一來源版本推薦">方法 A：單一來源版本（推薦）</h5>
<p>在 <code>__init__.py</code> 中定義版本：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># src/claude_hooks_lib/__init__.py</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="s2">Claude Hooks Library
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="s2">Shared utilities for building Claude Code hooks.
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="s2">&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">__version__</span> <span class="o">=</span> <span class="s2">&#34;0.28.0&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="c1"># Version</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="s2">&#34;__version__&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="c1"># git_utils</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="s2">&#34;run_git_command&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="s2">&#34;get_current_branch&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="s2">&#34;get_project_root&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="s2">&#34;get_worktree_list&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="s2">&#34;is_protected_branch&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="s2">&#34;is_allowed_branch&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="c1"># hook_logging</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="s2">&#34;setup_hook_logging&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">    <span class="c1"># hook_io</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">    <span class="s2">&#34;read_hook_input&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">    <span class="s2">&#34;write_hook_output&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">    <span class="s2">&#34;create_pretooluse_output&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="s2">&#34;create_posttooluse_output&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">    <span class="c1"># config_loader</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">    <span class="s2">&#34;load_config&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">    <span class="s2">&#34;load_agents_config&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">    <span class="s2">&#34;load_quality_rules&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">    <span class="s2">&#34;clear_config_cache&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="kn">from</span> <span class="nn">.git_utils</span> <span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">    <span class="n">run_git_command</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">    <span class="n">get_current_branch</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">    <span class="n">get_project_root</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">    <span class="n">get_worktree_list</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">    <span class="n">is_protected_branch</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl">    <span class="n">is_allowed_branch</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">
</span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="kn">from</span> <span class="nn">.hook_logging</span> <span class="kn">import</span> <span class="n">setup_hook_logging</span>
</span></span><span class="line"><span class="ln">43</span><span class="cl">
</span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="kn">from</span> <span class="nn">.hook_io</span> <span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln">45</span><span class="cl">    <span class="n">read_hook_input</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">46</span><span class="cl">    <span class="n">write_hook_output</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">47</span><span class="cl">    <span class="n">create_pretooluse_output</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">48</span><span class="cl">    <span class="n">create_posttooluse_output</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">50</span><span class="cl">
</span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="kn">from</span> <span class="nn">.config_loader</span> <span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln">52</span><span class="cl">    <span class="n">load_config</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">53</span><span class="cl">    <span class="n">load_agents_config</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">54</span><span class="cl">    <span class="n">load_quality_rules</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">55</span><span class="cl">    <span class="n">clear_config_cache</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="p">)</span></span></span></code></pre></div><p>在 <code>pyproject.toml</code> 中使用動態版本：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;claude-hooks-lib&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nx">dynamic</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;version&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">version</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nx">path</span> <span class="p">=</span> <span class="s2">&#34;src/claude_hooks_lib/__init__.py&#34;</span></span></span></code></pre></div><h5 id="方法-b使用-hatch-vcsgit-tag-版本">方法 B：使用 hatch-vcs（Git tag 版本）</h5>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">build-system</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nx">requires</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;hatchling&#34;</span><span class="p">,</span> <span class="s2">&#34;hatch-vcs&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">build-backend</span> <span class="p">=</span> <span class="s2">&#34;hatchling.build&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nx">dynamic</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;version&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">version</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nx">source</span> <span class="p">=</span> <span class="s2">&#34;vcs&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">build</span><span class="p">.</span><span class="nx">hooks</span><span class="p">.</span><span class="nx">vcs</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nx">version-file</span> <span class="p">=</span> <span class="s2">&#34;src/claude_hooks_lib/_version.py&#34;</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># Create version tag</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">git tag v0.28.0
</span></span><span class="line"><span class="ln">3</span><span class="cl">git push --tags</span></span></code></pre></div><h4 id="步驟-5建立發布流程">步驟 5：建立發布流程</h4>
<p><strong>.github/workflows/publish.yml</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Publish to PyPI</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">  </span><span class="nt">release</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="nt">types</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">published]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w"></span><span class="nt">permissions</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">  </span><span class="nt">contents</span><span class="p">:</span><span class="w"> </span><span class="l">read</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">  </span><span class="nt">id-token</span><span class="p">:</span><span class="w"> </span><span class="l">write </span><span class="w"> </span><span class="c"># Required for trusted publishing</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w"></span><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">  </span><span class="nt">build</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Set up Python</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/setup-python@v5</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">          </span><span class="nt">python-version</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;3.12&#34;</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Install build tools</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="sd">          python -m pip install --upgrade pip
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="sd">          pip install build</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Build package</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">python -m build</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Upload artifacts</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/upload-artifact@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">dist</span><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">          </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">dist/</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">  </span><span class="nt">test</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w">    </span><span class="nt">strategy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w">      </span><span class="nt">matrix</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w">        </span><span class="nt">python-version</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;3.10&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;3.11&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;3.12&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;3.13&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Set up Python ${{ matrix.python-version }}</span><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/setup-python@v5</span><span class="w">
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="w">          </span><span class="nt">python-version</span><span class="p">:</span><span class="w"> </span><span class="l">${{ matrix.python-version }}</span><span class="w">
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Install dependencies</span><span class="w">
</span></span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="sd">          python -m pip install --upgrade pip
</span></span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="sd">          pip install -e &#34;.[dev,yaml]&#34;</span><span class="w">
</span></span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">54</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Run tests</span><span class="w">
</span></span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">pytest tests/ -v --cov=src/claude_hooks_lib</span><span class="w">
</span></span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">57</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Type check</span><span class="w">
</span></span></span><span class="line"><span class="ln">58</span><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">mypy src/claude_hooks_lib</span><span class="w">
</span></span></span><span class="line"><span class="ln">59</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">60</span><span class="cl"><span class="w">  </span><span class="nt">publish-testpypi</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">61</span><span class="cl"><span class="w">    </span><span class="nt">needs</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">build, test]</span><span class="w">
</span></span></span><span class="line"><span class="ln">62</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="ln">63</span><span class="cl"><span class="w">    </span><span class="nt">environment</span><span class="p">:</span><span class="w"> </span><span class="l">testpypi</span><span class="w">
</span></span></span><span class="line"><span class="ln">64</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">65</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Download artifacts</span><span class="w">
</span></span></span><span class="line"><span class="ln">66</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/download-artifact@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln">67</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">68</span><span class="cl"><span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">dist</span><span class="w">
</span></span></span><span class="line"><span class="ln">69</span><span class="cl"><span class="w">          </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">dist/</span><span class="w">
</span></span></span><span class="line"><span class="ln">70</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">71</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Publish to TestPyPI</span><span class="w">
</span></span></span><span class="line"><span class="ln">72</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">pypa/gh-action-pypi-publish@release/v1</span><span class="w">
</span></span></span><span class="line"><span class="ln">73</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">74</span><span class="cl"><span class="w">          </span><span class="nt">repository-url</span><span class="p">:</span><span class="w"> </span><span class="l">https://test.pypi.org/legacy/</span><span class="w">
</span></span></span><span class="line"><span class="ln">75</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">76</span><span class="cl"><span class="w">  </span><span class="nt">publish-pypi</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">77</span><span class="cl"><span class="w">    </span><span class="nt">needs</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">publish-testpypi]</span><span class="w">
</span></span></span><span class="line"><span class="ln">78</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="ln">79</span><span class="cl"><span class="w">    </span><span class="nt">environment</span><span class="p">:</span><span class="w"> </span><span class="l">pypi</span><span class="w">
</span></span></span><span class="line"><span class="ln">80</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">81</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Download artifacts</span><span class="w">
</span></span></span><span class="line"><span class="ln">82</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/download-artifact@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln">83</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">84</span><span class="cl"><span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">dist</span><span class="w">
</span></span></span><span class="line"><span class="ln">85</span><span class="cl"><span class="w">          </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">dist/</span><span class="w">
</span></span></span><span class="line"><span class="ln">86</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">87</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Publish to PyPI</span><span class="w">
</span></span></span><span class="line"><span class="ln">88</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">pypa/gh-action-pypi-publish@release/v1</span></span></span></code></pre></div><p><strong>CI 測試工作流程（.github/workflows/test.yml）</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Tests</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">main]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">  </span><span class="nt">pull_request</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">main]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w"></span><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">  </span><span class="nt">test</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">${{ matrix.os }}</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="nt">strategy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">      </span><span class="nt">fail-fast</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">      </span><span class="nt">matrix</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">        </span><span class="nt">os</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">ubuntu-latest, macos-latest, windows-latest]</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">        </span><span class="nt">python-version</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;3.10&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;3.11&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;3.12&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;3.13&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Set up Python ${{ matrix.python-version }}</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/setup-python@v5</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">          </span><span class="nt">python-version</span><span class="p">:</span><span class="w"> </span><span class="l">${{ matrix.python-version }}</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Install dependencies</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="sd">          python -m pip install --upgrade pip
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="sd">          pip install -e &#34;.[dev,yaml]&#34;</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Lint with ruff</span><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">ruff check src/ tests/</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Format check with ruff</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">ruff format --check src/ tests/</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Type check with mypy</span><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">mypy src/claude_hooks_lib</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Run tests with coverage</span><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w">        </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="sd">          pytest tests/ -v --cov=src/claude_hooks_lib --cov-report=xml</span><span class="w">
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Upload coverage</span><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">codecov/codecov-action@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="w">          </span><span class="nt">files</span><span class="p">:</span><span class="w"> </span><span class="l">./coverage.xml</span></span></span></code></pre></div><h3 id="完整程式碼">完整程式碼</h3>
<h4 id="完整的-pyprojecttoml">完整的 pyproject.toml</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln">  1</span><span class="cl"><span class="p">[</span><span class="nx">build-system</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">  2</span><span class="cl"><span class="nx">requires</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;hatchling&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">  3</span><span class="cl"><span class="nx">build-backend</span> <span class="p">=</span> <span class="s2">&#34;hatchling.build&#34;</span>
</span></span><span class="line"><span class="ln">  4</span><span class="cl">
</span></span><span class="line"><span class="ln">  5</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">  6</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;claude-hooks-lib&#34;</span>
</span></span><span class="line"><span class="ln">  7</span><span class="cl"><span class="nx">dynamic</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;version&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">  8</span><span class="cl"><span class="nx">description</span> <span class="p">=</span> <span class="s2">&#34;Shared utilities for Claude Code hooks&#34;</span>
</span></span><span class="line"><span class="ln">  9</span><span class="cl"><span class="nx">readme</span> <span class="p">=</span> <span class="s2">&#34;README.md&#34;</span>
</span></span><span class="line"><span class="ln"> 10</span><span class="cl"><span class="nx">license</span> <span class="p">=</span> <span class="s2">&#34;MIT&#34;</span>
</span></span><span class="line"><span class="ln"> 11</span><span class="cl"><span class="nx">requires-python</span> <span class="p">=</span> <span class="s2">&#34;&gt;=3.10&#34;</span>
</span></span><span class="line"><span class="ln"> 12</span><span class="cl"><span class="nx">authors</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 13</span><span class="cl">    <span class="p">{</span> <span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;Your Name&#34;</span><span class="p">,</span> <span class="nx">email</span> <span class="p">=</span> <span class="s2">&#34;your.email@example.com&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 14</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 15</span><span class="cl"><span class="nx">keywords</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;claude&#34;</span><span class="p">,</span> <span class="s2">&#34;hooks&#34;</span><span class="p">,</span> <span class="s2">&#34;utilities&#34;</span><span class="p">,</span> <span class="s2">&#34;git&#34;</span><span class="p">,</span> <span class="s2">&#34;automation&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 16</span><span class="cl"><span class="nx">classifiers</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 17</span><span class="cl">    <span class="s2">&#34;Development Status :: 4 - Beta&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 18</span><span class="cl">    <span class="s2">&#34;Intended Audience :: Developers&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 19</span><span class="cl">    <span class="s2">&#34;License :: OSI Approved :: MIT License&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 20</span><span class="cl">    <span class="s2">&#34;Operating System :: OS Independent&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 21</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: 3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 22</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: 3.10&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 23</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: 3.11&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 24</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: 3.12&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 25</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: 3.13&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 26</span><span class="cl">    <span class="s2">&#34;Typing :: Typed&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 27</span><span class="cl">    <span class="s2">&#34;Topic :: Software Development :: Libraries :: Python Modules&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 28</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 29</span><span class="cl">
</span></span><span class="line"><span class="ln"> 30</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln"> 31</span><span class="cl">
</span></span><span class="line"><span class="ln"> 32</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">optional-dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 33</span><span class="cl"><span class="nx">yaml</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;PyYAML&gt;=6.0&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 34</span><span class="cl"><span class="nx">dev</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 35</span><span class="cl">    <span class="s2">&#34;pytest&gt;=8.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 36</span><span class="cl">    <span class="s2">&#34;pytest-cov&gt;=4.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 37</span><span class="cl">    <span class="s2">&#34;mypy&gt;=1.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 38</span><span class="cl">    <span class="s2">&#34;ruff&gt;=0.4&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 39</span><span class="cl">    <span class="s2">&#34;PyYAML&gt;=6.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 40</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 41</span><span class="cl"><span class="nx">docs</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 42</span><span class="cl">    <span class="s2">&#34;mkdocs&gt;=1.5&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 43</span><span class="cl">    <span class="s2">&#34;mkdocs-material&gt;=9.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 44</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 45</span><span class="cl"><span class="nx">all</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;claude-hooks-lib[yaml,dev,docs]&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 46</span><span class="cl">
</span></span><span class="line"><span class="ln"> 47</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">urls</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 48</span><span class="cl"><span class="nx">Homepage</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/yourname/claude-hooks-lib&#34;</span>
</span></span><span class="line"><span class="ln"> 49</span><span class="cl"><span class="nx">Documentation</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/yourname/claude-hooks-lib#readme&#34;</span>
</span></span><span class="line"><span class="ln"> 50</span><span class="cl"><span class="nx">Repository</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/yourname/claude-hooks-lib.git&#34;</span>
</span></span><span class="line"><span class="ln"> 51</span><span class="cl"><span class="nx">Changelog</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/yourname/claude-hooks-lib/blob/main/CHANGELOG.md&#34;</span>
</span></span><span class="line"><span class="ln"> 52</span><span class="cl">
</span></span><span class="line"><span class="ln"> 53</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">scripts</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 54</span><span class="cl"><span class="nx">hook-validator</span> <span class="p">=</span> <span class="s2">&#34;claude_hooks_lib.hook_validator:main&#34;</span>
</span></span><span class="line"><span class="ln"> 55</span><span class="cl">
</span></span><span class="line"><span class="ln"> 56</span><span class="cl"><span class="c"># ===== Build Configuration =====</span>
</span></span><span class="line"><span class="ln"> 57</span><span class="cl">
</span></span><span class="line"><span class="ln"> 58</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">version</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 59</span><span class="cl"><span class="nx">path</span> <span class="p">=</span> <span class="s2">&#34;src/claude_hooks_lib/__init__.py&#34;</span>
</span></span><span class="line"><span class="ln"> 60</span><span class="cl">
</span></span><span class="line"><span class="ln"> 61</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">build</span><span class="p">.</span><span class="nx">targets</span><span class="p">.</span><span class="nx">sdist</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 62</span><span class="cl"><span class="nx">include</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;/src&#34;</span><span class="p">,</span> <span class="s2">&#34;/tests&#34;</span><span class="p">,</span> <span class="s2">&#34;/README.md&#34;</span><span class="p">,</span> <span class="s2">&#34;/LICENSE&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 63</span><span class="cl">
</span></span><span class="line"><span class="ln"> 64</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">build</span><span class="p">.</span><span class="nx">targets</span><span class="p">.</span><span class="nx">wheel</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 65</span><span class="cl"><span class="nx">packages</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;src/claude_hooks_lib&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 66</span><span class="cl">
</span></span><span class="line"><span class="ln"> 67</span><span class="cl"><span class="c"># ===== Tool Configuration =====</span>
</span></span><span class="line"><span class="ln"> 68</span><span class="cl">
</span></span><span class="line"><span class="ln"> 69</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">ruff</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 70</span><span class="cl"><span class="nx">src</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;src&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 71</span><span class="cl"><span class="nx">line-length</span> <span class="p">=</span> <span class="mi">88</span>
</span></span><span class="line"><span class="ln"> 72</span><span class="cl"><span class="nx">target-version</span> <span class="p">=</span> <span class="s2">&#34;py310&#34;</span>
</span></span><span class="line"><span class="ln"> 73</span><span class="cl">
</span></span><span class="line"><span class="ln"> 74</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">ruff</span><span class="p">.</span><span class="nx">lint</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 75</span><span class="cl"><span class="nx">select</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 76</span><span class="cl">    <span class="s2">&#34;E&#34;</span><span class="p">,</span>      <span class="c"># pycodestyle errors</span>
</span></span><span class="line"><span class="ln"> 77</span><span class="cl">    <span class="s2">&#34;W&#34;</span><span class="p">,</span>      <span class="c"># pycodestyle warnings</span>
</span></span><span class="line"><span class="ln"> 78</span><span class="cl">    <span class="s2">&#34;F&#34;</span><span class="p">,</span>      <span class="c"># pyflakes</span>
</span></span><span class="line"><span class="ln"> 79</span><span class="cl">    <span class="s2">&#34;I&#34;</span><span class="p">,</span>      <span class="c"># isort</span>
</span></span><span class="line"><span class="ln"> 80</span><span class="cl">    <span class="s2">&#34;B&#34;</span><span class="p">,</span>      <span class="c"># flake8-bugbear</span>
</span></span><span class="line"><span class="ln"> 81</span><span class="cl">    <span class="s2">&#34;C4&#34;</span><span class="p">,</span>     <span class="c"># flake8-comprehensions</span>
</span></span><span class="line"><span class="ln"> 82</span><span class="cl">    <span class="s2">&#34;UP&#34;</span><span class="p">,</span>     <span class="c"># pyupgrade</span>
</span></span><span class="line"><span class="ln"> 83</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 84</span><span class="cl"><span class="nx">ignore</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;E501&#34;</span><span class="p">]</span>  <span class="c"># Line too long (handled by formatter)</span>
</span></span><span class="line"><span class="ln"> 85</span><span class="cl">
</span></span><span class="line"><span class="ln"> 86</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">ruff</span><span class="p">.</span><span class="nx">lint</span><span class="p">.</span><span class="nx">isort</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 87</span><span class="cl"><span class="nx">known-first-party</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;claude_hooks_lib&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 88</span><span class="cl">
</span></span><span class="line"><span class="ln"> 89</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">mypy</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 90</span><span class="cl"><span class="nx">python_version</span> <span class="p">=</span> <span class="s2">&#34;3.10&#34;</span>
</span></span><span class="line"><span class="ln"> 91</span><span class="cl"><span class="nx">warn_return_any</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln"> 92</span><span class="cl"><span class="nx">warn_unused_ignores</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln"> 93</span><span class="cl"><span class="nx">disallow_untyped_defs</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln"> 94</span><span class="cl"><span class="nx">strict</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln"> 95</span><span class="cl">
</span></span><span class="line"><span class="ln"> 96</span><span class="cl"><span class="p">[[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">mypy</span><span class="p">.</span><span class="nx">overrides</span><span class="p">]]</span>
</span></span><span class="line"><span class="ln"> 97</span><span class="cl"><span class="nx">module</span> <span class="p">=</span> <span class="s2">&#34;yaml&#34;</span>
</span></span><span class="line"><span class="ln"> 98</span><span class="cl"><span class="nx">ignore_missing_imports</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln"> 99</span><span class="cl">
</span></span><span class="line"><span class="ln">100</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">pytest</span><span class="p">.</span><span class="nx">ini_options</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">101</span><span class="cl"><span class="nx">testpaths</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;tests&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">102</span><span class="cl"><span class="nx">python_files</span> <span class="p">=</span> <span class="s2">&#34;test_*.py&#34;</span>
</span></span><span class="line"><span class="ln">103</span><span class="cl"><span class="nx">python_functions</span> <span class="p">=</span> <span class="s2">&#34;test_*&#34;</span>
</span></span><span class="line"><span class="ln">104</span><span class="cl"><span class="nx">addopts</span> <span class="p">=</span> <span class="s2">&#34;-v --tb=short&#34;</span>
</span></span><span class="line"><span class="ln">105</span><span class="cl">
</span></span><span class="line"><span class="ln">106</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">coverage</span><span class="p">.</span><span class="nx">run</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">107</span><span class="cl"><span class="nx">source</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;src/claude_hooks_lib&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">108</span><span class="cl"><span class="nx">branch</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln">109</span><span class="cl">
</span></span><span class="line"><span class="ln">110</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">coverage</span><span class="p">.</span><span class="nx">report</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">111</span><span class="cl"><span class="nx">exclude_lines</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">112</span><span class="cl">    <span class="s2">&#34;pragma: no cover&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">113</span><span class="cl">    <span class="s2">&#34;if TYPE_CHECKING:&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">114</span><span class="cl">    <span class="s2">&#34;raise NotImplementedError&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">115</span><span class="cl"><span class="p">]</span></span></span></code></pre></div><h3 id="使用範例">使用範例</h3>
<h4 id="安裝套件">安裝套件</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># From PyPI (after publishing)</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">pip install claude-hooks-lib
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># With YAML support</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">pip install <span class="s2">&#34;claude-hooks-lib[yaml]&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># Development installation (from source)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">git clone https://github.com/yourname/claude-hooks-lib
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nb">cd</span> claude-hooks-lib
</span></span><span class="line"><span class="ln">10</span><span class="cl">pip install -e <span class="s2">&#34;.[dev]&#34;</span></span></span></code></pre></div><h5 id="python-使用範例">Python 使用範例</h5>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># Basic usage</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">from</span> <span class="nn">claude_hooks_lib</span> <span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="n">get_current_branch</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="n">is_protected_branch</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="n">setup_hook_logging</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">read_hook_input</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">write_hook_output</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">create_pretooluse_output</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"># Initialize logging</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">logger</span> <span class="o">=</span> <span class="n">setup_hook_logging</span><span class="p">(</span><span class="s2">&#34;my-custom-hook&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"># Check branch protection</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">branch</span> <span class="o">=</span> <span class="n">get_current_branch</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="k">if</span> <span class="n">branch</span> <span class="ow">and</span> <span class="n">is_protected_branch</span><span class="p">(</span><span class="n">branch</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Operating on protected branch: </span><span class="si">{</span><span class="n">branch</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="c1"># Process hook input</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="n">input_data</span> <span class="o">=</span> <span class="n">read_hook_input</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="n">tool_name</span> <span class="o">=</span> <span class="n">input_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;tool_name&#34;</span><span class="p">,</span> <span class="s2">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="c1"># Generate output</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="n">output</span> <span class="o">=</span> <span class="n">create_pretooluse_output</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="n">decision</span><span class="o">=</span><span class="s2">&#34;allow&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">    <span class="n">reason</span><span class="o">=</span><span class="s2">&#34;All checks passed&#34;</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="n">write_hook_output</span><span class="p">(</span><span class="n">output</span><span class="p">)</span></span></span></code></pre></div><h4 id="命令列工具使用">命令列工具使用</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># Validate a single hook</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">hook-validator .claude/hooks/my-hook.py
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># Validate all hooks</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">hook-validator --all
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># Output as JSON</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">hook-validator --all --json
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># Strict mode (warnings as errors)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">hook-validator --all --strict</span></span></code></pre></div><h2 id="設計權衡">設計權衡</h2>
<table>
  <thead>
      <tr>
          <th>面向</th>
          <th>內部目錄</th>
          <th>獨立套件</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>重用性</strong></td>
          <td>僅限單專案</td>
          <td>跨專案共用</td>
      </tr>
      <tr>
          <td><strong>版本管理</strong></td>
          <td>與專案綁定</td>
          <td>獨立語意化版本</td>
      </tr>
      <tr>
          <td><strong>維護成本</strong></td>
          <td>低（無發布流程）</td>
          <td>中（需維護 CI/CD）</td>
      </tr>
      <tr>
          <td><strong>相依管理</strong></td>
          <td>隱式（需手動追蹤）</td>
          <td>顯式（pyproject.toml）</td>
      </tr>
      <tr>
          <td><strong>安裝方式</strong></td>
          <td>複製程式碼或 sys.path</td>
          <td>pip install</td>
      </tr>
      <tr>
          <td><strong>測試隔離</strong></td>
          <td>可能測試到本地版本</td>
          <td>強制測試安裝版本</td>
      </tr>
      <tr>
          <td><strong>API 穩定性</strong></td>
          <td>無保證</td>
          <td>版本號約束</td>
      </tr>
  </tbody>
</table>
<h3 id="專案結構比較">專案結構比較</h3>
<table>
  <thead>
      <tr>
          <th>Layout</th>
          <th>適用場景</th>
          <th>優點</th>
          <th>缺點</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Flat Layout</strong></td>
          <td>簡單應用、腳本</td>
          <td>簡單直覺</td>
          <td>測試可能導入錯誤版本</td>
      </tr>
      <tr>
          <td><strong>Src Layout</strong></td>
          <td>函式庫、套件發布</td>
          <td>測試隔離、明確邊界</td>
          <td>額外一層目錄</td>
      </tr>
  </tbody>
</table>
<h3 id="建構工具比較">建構工具比較</h3>
<table>
  <thead>
      <tr>
          <th>工具</th>
          <th>特點</th>
          <th>推薦場景</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>setuptools</strong></td>
          <td>成熟穩定、生態最大</td>
          <td>需要相容舊專案</td>
      </tr>
      <tr>
          <td><strong>Hatch</strong></td>
          <td>現代、快速、功能完整</td>
          <td>新專案首選</td>
      </tr>
      <tr>
          <td><strong>Poetry</strong></td>
          <td>依賴鎖定、虛擬環境管理</td>
          <td>需要嚴格依賴控制</td>
      </tr>
      <tr>
          <td><strong>Flit</strong></td>
          <td>極簡、僅純 Python</td>
          <td>簡單函式庫</td>
      </tr>
  </tbody>
</table>
<h2 id="什麼時候該打包成套件">什麼時候該打包成套件？</h2>
<h3 id="適合打包">適合打包</h3>
<ul>
<li>多個專案需要使用相同程式碼</li>
<li>程式碼相對穩定，API 不常變動</li>
<li>需要版本控制和變更追蹤</li>
<li>希望其他人能 pip install 使用</li>
<li>需要明確的相依性管理</li>
</ul>
<h3 id="不建議打包">不建議打包</h3>
<ul>
<li>僅單一專案使用</li>
<li>程式碼還在快速迭代</li>
<li>與專案緊密耦合（如特定的配置路徑）</li>
<li>維護成本超過重用收益</li>
</ul>
<h3 id="決策流程圖">決策流程圖</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">程式碼需要跨專案使用？
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── 否 → 保持內部目錄
</span></span><span class="line"><span class="ln">3</span><span class="cl">└── 是 → API 穩定嗎？
</span></span><span class="line"><span class="ln">4</span><span class="cl">         ├── 否 → 等待穩定後再打包
</span></span><span class="line"><span class="ln">5</span><span class="cl">         └── 是 → 有維護能力嗎？
</span></span><span class="line"><span class="ln">6</span><span class="cl">                  ├── 否 → 考慮 monorepo
</span></span><span class="line"><span class="ln">7</span><span class="cl">                  └── 是 → 打包發布</span></span></code></pre></div><h2 id="練習">練習</h2>
<h3 id="基礎練習建立最小的-pyprojecttoml">基礎練習：建立最小的 pyproject.toml</h3>
<p><strong>目標</strong>：為一個簡單的工具函式庫建立 pyproject.toml</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># src/my_utils/__init__.py</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="s2">&#34;&#34;&#34;Simple utilities.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">__version__</span> <span class="o">=</span> <span class="s2">&#34;0.1.0&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Return a greeting message.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">    <span class="k">return</span> <span class="sa">f</span><span class="s2">&#34;Hello, </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">!&#34;</span></span></span></code></pre></div><p><strong>要求</strong>：</p>
<ol>
<li>使用 hatchling 作為建構後端</li>
<li>設定專案名稱、版本、描述</li>
<li>指定 Python 版本要求（&gt;=3.10）</li>
</ol>
<details>
<summary>參考答案</summary>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">build-system</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nx">requires</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;hatchling&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">build-backend</span> <span class="p">=</span> <span class="s2">&#34;hatchling.build&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;my-utils&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.1.0&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">description</span> <span class="p">=</span> <span class="s2">&#34;Simple utility functions&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nx">requires-python</span> <span class="p">=</span> <span class="s2">&#34;&gt;=3.10&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">build</span><span class="p">.</span><span class="nx">targets</span><span class="p">.</span><span class="nx">wheel</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nx">packages</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;src/my_utils&#34;</span><span class="p">]</span></span></span></code></pre></div></details>
<h3 id="進階練習新增-optional-dependencies">進階練習：新增 optional dependencies</h3>
<p><strong>目標</strong>：擴展上面的套件，加入可選的功能</p>
<p><strong>要求</strong>：</p>
<ol>
<li>新增一個需要 <code>requests</code> 的函式</li>
<li>將 <code>requests</code> 設為可選相依性</li>
<li>加入開發相依性（pytest, ruff）</li>
</ol>
<details>
<summary>參考答案</summary>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">build-system</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nx">requires</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;hatchling&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">build-backend</span> <span class="p">=</span> <span class="s2">&#34;hatchling.build&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;my-utils&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;0.1.0&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">description</span> <span class="p">=</span> <span class="s2">&#34;Simple utility functions&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nx">requires-python</span> <span class="p">=</span> <span class="s2">&#34;&gt;=3.10&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">optional-dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nx">http</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;requests&gt;=2.28&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="nx">dev</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="s2">&#34;pytest&gt;=8.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="s2">&#34;ruff&gt;=0.4&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="s2">&#34;my-utils[http]&#34;</span><span class="p">,</span>  <span class="c"># Include http for testing</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">build</span><span class="p">.</span><span class="nx">targets</span><span class="p">.</span><span class="nx">wheel</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="nx">packages</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;src/my_utils&#34;</span><span class="p">]</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># src/my_utils/http.py</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="s2">&#34;&#34;&#34;HTTP utilities (requires requests).&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="kn">import</span> <span class="nn">requests</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="n">HAS_REQUESTS</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">HAS_REQUESTS</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="k">def</span> <span class="nf">fetch_json</span><span class="p">(</span><span class="n">url</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Fetch JSON from URL.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="k">if</span> <span class="ow">not</span> <span class="n">HAS_REQUESTS</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">        <span class="k">raise</span> <span class="ne">ImportError</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">            <span class="s2">&#34;requests is required for this feature. &#34;</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">            <span class="s2">&#34;Install with: pip install my-utils[http]&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="n">response</span><span class="o">.</span><span class="n">raise_for_status</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="k">return</span> <span class="n">response</span><span class="o">.</span><span class="n">json</span><span class="p">()</span></span></span></code></pre></div></details>
<h3 id="挑戰題設定-github-actions-自動發布到-pypi">挑戰題：設定 GitHub Actions 自動發布到 PyPI</h3>
<p><strong>目標</strong>：建立完整的 CI/CD 流程</p>
<p><strong>要求</strong>：</p>
<ol>
<li>Pull Request 時執行測試</li>
<li>建立 Release 時自動發布到 PyPI</li>
<li>使用 Trusted Publishing（不需要 API Token）</li>
<li>多版本 Python 測試矩陣</li>
</ol>
<p><strong>提示</strong>：</p>
<ul>
<li>需要在 PyPI 設定 Trusted Publisher</li>
<li>使用 <code>pypa/gh-action-pypi-publish@release/v1</code></li>
<li>設定 <code>id-token: write</code> 權限</li>
</ul>
<details>
<summary>參考答案</summary>
<ol>
<li>
<p>先在 PyPI 設定 Trusted Publisher：</p>
<ul>
<li>前往 <a href="https://pypi.org/manage/account/publishing/">pypi.org</a></li>
<li>新增 GitHub publisher</li>
<li>填入 repository owner、name、workflow 路徑</li>
</ul>
</li>
<li>
<p>建立工作流程檔案：</p>
</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c"># .github/workflows/ci.yml</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">CI</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">main]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">  </span><span class="nt">pull_request</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">main]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w"></span><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">  </span><span class="nt">test</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="nt">strategy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">      </span><span class="nt">matrix</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">        </span><span class="nt">python-version</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;3.10&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;3.11&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;3.12&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;3.13&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/setup-python@v5</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">          </span><span class="nt">python-version</span><span class="p">:</span><span class="w"> </span><span class="l">${{ matrix.python-version }}</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">      </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">pip install -e &#34;.[dev]&#34;</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">      </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">ruff check src/ tests/</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">      </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">pytest tests/ -v</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c"># .github/workflows/publish.yml</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Publish</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">  </span><span class="nt">release</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="nt">types</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">published]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w"></span><span class="nt">permissions</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">  </span><span class="nt">contents</span><span class="p">:</span><span class="w"> </span><span class="l">read</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">  </span><span class="nt">id-token</span><span class="p">:</span><span class="w"> </span><span class="l">write</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">  </span><span class="nt">publish</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">    </span><span class="nt">environment</span><span class="p">:</span><span class="w"> </span><span class="l">pypi</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/setup-python@v5</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">          </span><span class="nt">python-version</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;3.12&#34;</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">      </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">pip install build</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">      </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">python -m build</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">pypa/gh-action-pypi-publish@release/v1</span></span></span></code></pre></div></details>
<h2 id="延伸閱讀">延伸閱讀</h2>
<ul>
<li><a href="https://packaging.python.org/">Python 打包使用者指南</a></li>
<li><a href="https://peps.python.org/pep-0621/">pyproject.toml 規範 (PEP 621)</a></li>
<li><a href="https://hatch.pypa.io/">Hatch 建置工具</a></li>
<li><a href="https://docs.pypi.org/trusted-publishers/">Trusted Publishers (PyPI)</a></li>
</ul>
<hr>
<p>返回：<a href="/blog/python-advanced/07-packaging/" data-link-title="模組七：打包與發布" data-link-desc="學習現代 Python 套件的打包與發布流程">模組六：打包與發布</a></p>
]]></content:encoded></item><item><title>案例：使用 Poetry 完整工作流</title><link>https://tarrragon.github.io/blog/python-advanced/07-packaging/case-studies/poetry-workflow/</link><pubDate>Wed, 21 Jan 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/python-advanced/07-packaging/case-studies/poetry-workflow/</guid><description>&lt;p>本案例展示如何使用 Poetry 管理現代 Python 專案的完整生命週期，從專案建立到套件發布。&lt;/p>
&lt;h2 id="先備知識">先備知識&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/python-advanced/07-packaging/build-systems/" data-link-title="6.2 建構系統比較" data-link-desc="比較 setuptools、Poetry、Hatch 等建構系統">建構系統比較&lt;/a>&lt;/li>
&lt;li>Python 虛擬環境基礎&lt;/li>
&lt;li>套件相依性概念&lt;/li>
&lt;/ul>
&lt;h2 id="問題背景">問題背景&lt;/h2>
&lt;h3 id="現代專案的挑戰">現代專案的挑戰&lt;/h3>
&lt;p>傳統的 Python 專案管理面臨以下問題：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">傳統工作流程的痛點：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">├── 相依性管理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">│ ├── requirements.txt 無法鎖定間接相依性
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">│ ├── pip freeze 產生的版本可能過於嚴格
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">│ └── 開發與生產環境相依性混在一起
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">├── 虛擬環境
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">│ ├── 需要手動建立和管理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">│ ├── 不同專案的環境容易混淆
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">│ └── 缺乏與專案的關聯性
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">├── 建構與發布
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">│ ├── setup.py 設定複雜
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">│ ├── 發布流程需要多個工具
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">│ └── 版本管理不一致
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">└── 團隊協作
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl"> ├── 環境難以重現
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl"> ├── 「在我電腦上可以跑」問題
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl"> └── 新成員上手困難&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="為什麼選擇-poetry">為什麼選擇 Poetry？&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>特性&lt;/th>
 &lt;th>pip + venv&lt;/th>
 &lt;th>Poetry&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>相依性鎖定&lt;/td>
 &lt;td>手動（pip freeze）&lt;/td>
 &lt;td>自動（poetry.lock）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>間接相依性追蹤&lt;/td>
 &lt;td>無&lt;/td>
 &lt;td>完整追蹤&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>虛擬環境管理&lt;/td>
 &lt;td>手動&lt;/td>
 &lt;td>自動整合&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>建構系統&lt;/td>
 &lt;td>需要額外工具&lt;/td>
 &lt;td>內建&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>發布流程&lt;/td>
 &lt;td>需要 twine&lt;/td>
 &lt;td>內建&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>相依性群組&lt;/td>
 &lt;td>無原生支援&lt;/td>
 &lt;td>完整支援&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="解決方案">解決方案&lt;/h2>
&lt;h3 id="安裝-poetry">安裝 Poetry&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 官方推薦的安裝方式（獨立安裝）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">curl -sSL https://install.python-poetry.org &lt;span class="p">|&lt;/span> python3 -
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 或使用 pipx（推薦用於 CLI 工具）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">pipx install poetry
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 確認安裝&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">poetry --version&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="設定-poetry">設定 Poetry&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 在專案目錄中建立虛擬環境（推薦）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">poetry config virtualenvs.in-project &lt;span class="nb">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 查看所有設定&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">poetry config --list&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="工作流一建立新專案">工作流一：建立新專案&lt;/h3>
&lt;h4 id="使用-poetry-new完整專案結構">使用 poetry new（完整專案結構）&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 建立新專案&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">poetry new my-awesome-lib
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 產生的目錄結構&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">my-awesome-lib/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">├── pyproject.toml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">├── README.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">├── my_awesome_lib/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">│ └── __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">└── tests/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> └── __init__.py&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 使用 src layout（推薦用於函式庫）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">poetry new --src my-awesome-lib
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 產生的目錄結構&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">my-awesome-lib/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">├── pyproject.toml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">├── README.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">├── src/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">│ └── my_awesome_lib/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">│ └── __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">└── tests/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl"> └── __init__.py&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="使用-poetry-init現有專案">使用 poetry init（現有專案）&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 在現有目錄初始化&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="nb">cd&lt;/span> existing-project
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">poetry init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="c1"># 互動式問答&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="c1"># - Package name&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1"># - Version&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="c1"># - Description&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="c1"># - Author&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="c1"># - License&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="c1"># - Python version&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1"># - Dependencies&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="互動式初始化範例">互動式初始化範例&lt;/h5>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">This command will guide you through creating your pyproject.toml config.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">Package name [existing-project]: my-package
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">Version [0.1.0]: 1.0.0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">Description []: A useful Python package
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">Author [Your Name &amp;lt;you@example.com&amp;gt;, n to skip]:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">License []: MIT
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">Compatible Python versions [^3.10]: ^3.10
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">Would you like to define your main dependencies interactively? (yes/no) [yes]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">Search for package to add (or leave blank to continue): requests
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">...&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="工作流二管理相依性">工作流二：管理相依性&lt;/h3>
&lt;h4 id="新增相依性">新增相依性&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 新增生產相依性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">poetry add requests
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">poetry add &lt;span class="s2">&amp;#34;httpx&amp;gt;=0.24&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="c1"># 新增開發相依性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">poetry add pytest --group dev
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">poetry add ruff mypy --group dev
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="c1"># 新增文件相依性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">poetry add mkdocs mkdocs-material --group docs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1"># 新增可選相依性（extras）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">poetry add pyyaml --optional&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="pyprojecttoml-的變化">pyproject.toml 的變化&lt;/h5>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="nx">python&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^3.10&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">requests&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^2.31.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="nx">httpx&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;gt;=0.24&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dev&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="nx">pytest&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^8.0.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">ruff&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^0.4.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="nx">mypy&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^1.10.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">docs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="nx">mkdocs&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^1.5.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="nx">mkdocs-material&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^9.5.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">extras&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="nx">yaml&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;pyyaml&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="移除相依性">移除相依性&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 移除生產相依性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">poetry remove requests
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 移除開發相依性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">poetry remove pytest --group dev&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="更新相依性">更新相依性&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 更新所有相依性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">poetry update
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 更新特定套件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">poetry update requests
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 檢視可更新的套件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">poetry show --outdated
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="c1"># 檢視相依性樹&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">poetry show --tree&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="相依性樹範例輸出">相依性樹範例輸出&lt;/h5>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">requests 2.31.0 Python HTTP for Humans.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">├── certifi &amp;gt;=2017.4.17
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">├── charset-normalizer &amp;gt;=2,&amp;lt;4
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">├── idna &amp;gt;=2.5,&amp;lt;4
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">└── urllib3 &amp;gt;=1.21.1,&amp;lt;3&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="工作流三虛擬環境管理">工作流三：虛擬環境管理&lt;/h3>
&lt;h4 id="自動環境管理">自動環境管理&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 安裝所有相依性（自動建立虛擬環境）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">poetry install
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 僅安裝生產相依性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">poetry install --only main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 安裝包含特定群組&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">poetry install --with dev,docs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="c1"># 排除特定群組&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">poetry install --without docs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="c1"># 安裝 extras&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">poetry install --extras yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">poetry install --all-extras&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="環境操作">環境操作&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 進入虛擬環境 shell&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">poetry shell
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 在虛擬環境中執行命令（不進入 shell）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">poetry run python script.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">poetry run pytest
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">poetry run python -c &lt;span class="s2">&amp;#34;import my_package; print(my_package.__version__)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="c1"># 顯示環境資訊&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">poetry env info
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1"># 顯示環境路徑&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">poetry env info --path
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="c1"># 列出所有環境&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">poetry env list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="c1"># 切換 Python 版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">poetry env use python3.11
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">poetry env use 3.12
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">&lt;span class="c1"># 刪除環境&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">poetry env remove python3.11
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl">poetry env remove --all&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="環境資訊範例輸出">環境資訊範例輸出&lt;/h5>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">Virtualenv
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">Python: 3.11.6
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">Implementation: CPython
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">Path: /path/to/project/.venv
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">Executable: /path/to/project/.venv/bin/python
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">Valid: True
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">Base
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">Platform: darwin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">OS: posix
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">Python: 3.11.6
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">Path: /opt/homebrew/Cellar/python@3.11/3.11.6/Frameworks/Python.framework/Versions/3.11
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">Executable: /opt/homebrew/Cellar/python@3.11/3.11.6/Frameworks/Python.framework/Versions/3.11/bin/python3.11&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="工作流四建構與發布">工作流四：建構與發布&lt;/h3>
&lt;h4 id="建構套件">建構套件&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 建構 sdist 和 wheel&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">poetry build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 僅建構 wheel&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">poetry build --format wheel
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 建構結果&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">dist/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">├── my_package-1.0.0-py3-none-any.whl
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">└── my_package-1.0.0.tar.gz&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="發布到-pypi">發布到 PyPI&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 設定 PyPI token&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">poetry config pypi-token.pypi pypi-XXXXXXXXXXXX
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 發布到 PyPI&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">poetry publish
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 建構並發布（一步完成）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">poetry publish --build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="c1"># 發布到 TestPyPI&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">poetry config repositories.testpypi https://test.pypi.org/legacy/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">poetry config pypi-token.testpypi pypi-XXXXXXXXXXXX
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">poetry publish --repository testpypi&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="版本管理">版本管理&lt;/h5>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 查看當前版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">poetry version
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 升級版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">poetry version patch &lt;span class="c1"># 1.0.0 -&amp;gt; 1.0.1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">poetry version minor &lt;span class="c1"># 1.0.0 -&amp;gt; 1.1.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">poetry version major &lt;span class="c1"># 1.0.0 -&amp;gt; 2.0.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="c1"># 設定特定版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">poetry version 2.0.0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1"># 預發布版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">poetry version prepatch &lt;span class="c1"># 1.0.0 -&amp;gt; 1.0.1a0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">poetry version preminor &lt;span class="c1"># 1.0.0 -&amp;gt; 1.1.0a0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">poetry version premajor &lt;span class="c1"># 1.0.0 -&amp;gt; 2.0.0a0&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="完整-pyprojecttoml-範例">完整 pyproject.toml 範例&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">build-system&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="nx">requires&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;poetry-core&amp;gt;=2.0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">build-backend&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;poetry.core.masonry.api&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my-awesome-lib&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;1.0.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">description&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;A feature-rich Python library&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="nx">readme&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;README.md&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="nx">license&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;MIT&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nx">requires-python&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;gt;=3.10&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="nx">authors&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl"> &lt;span class="p">{&lt;/span> &lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Your Name&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">email&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;you@example.com&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="nx">keywords&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;python&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;library&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;utilities&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="nx">classifiers&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Development Status :: 4 - Beta&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Intended Audience :: Developers&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;License :: OSI Approved :: MIT License&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Operating System :: OS Independent&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: 3&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: 3.10&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: 3.11&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: 3.12&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: 3.13&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Typing :: Typed&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">urls&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl">&lt;span class="nx">Homepage&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://github.com/yourname/my-awesome-lib&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl">&lt;span class="nx">Documentation&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://my-awesome-lib.readthedocs.io&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl">&lt;span class="nx">Repository&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://github.com/yourname/my-awesome-lib.git&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl">&lt;span class="nx">Changelog&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://github.com/yourname/my-awesome-lib/blob/main/CHANGELOG.md&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">34&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">35&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">scripts&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">36&lt;/span>&lt;span class="cl">&lt;span class="nx">my-cli&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my_awesome_lib.cli:main&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">37&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">38&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">optional-dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">39&lt;/span>&lt;span class="cl">&lt;span class="nx">yaml&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;pyyaml&amp;gt;=6.0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">40&lt;/span>&lt;span class="cl">&lt;span class="nx">all&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;my-awesome-lib[yaml]&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">41&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">42&lt;/span>&lt;span class="cl">&lt;span class="c"># ===== Poetry 特定設定 =====&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">43&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">44&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">45&lt;/span>&lt;span class="cl">&lt;span class="nx">packages&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[{&lt;/span> &lt;span class="nx">include&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my_awesome_lib&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">from&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;src&amp;#34;&lt;/span> &lt;span class="p">}]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">46&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">47&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">48&lt;/span>&lt;span class="cl">&lt;span class="nx">python&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^3.10&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">49&lt;/span>&lt;span class="cl">&lt;span class="nx">requests&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^2.31&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">50&lt;/span>&lt;span class="cl">&lt;span class="nx">click&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^8.1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">51&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">52&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dev&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">53&lt;/span>&lt;span class="cl">&lt;span class="nx">pytest&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^8.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">54&lt;/span>&lt;span class="cl">&lt;span class="nx">pytest-cov&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^4.1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">55&lt;/span>&lt;span class="cl">&lt;span class="nx">pytest-asyncio&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^0.23&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">56&lt;/span>&lt;span class="cl">&lt;span class="nx">mypy&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^1.10&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">57&lt;/span>&lt;span class="cl">&lt;span class="nx">ruff&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^0.4&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">58&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">59&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">docs&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">60&lt;/span>&lt;span class="cl">&lt;span class="nx">optional&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">61&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">62&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">docs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">63&lt;/span>&lt;span class="cl">&lt;span class="nx">mkdocs&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^1.5&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">64&lt;/span>&lt;span class="cl">&lt;span class="nx">mkdocs-material&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^9.5&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">65&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">66&lt;/span>&lt;span class="cl">&lt;span class="c"># ===== 工具設定 =====&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">67&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">68&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ruff&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">69&lt;/span>&lt;span class="cl">&lt;span class="nx">src&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;src&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">70&lt;/span>&lt;span class="cl">&lt;span class="nx">line-length&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="mi">88&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">71&lt;/span>&lt;span class="cl">&lt;span class="nx">target-version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;py310&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">72&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">73&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ruff&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">lint&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">74&lt;/span>&lt;span class="cl">&lt;span class="nx">select&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;E&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;W&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;F&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;I&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;B&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;C4&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;UP&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">75&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">76&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">mypy&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">77&lt;/span>&lt;span class="cl">&lt;span class="nx">python_version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;3.10&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">78&lt;/span>&lt;span class="cl">&lt;span class="nx">strict&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">79&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">80&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">pytest&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ini_options&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">81&lt;/span>&lt;span class="cl">&lt;span class="nx">testpaths&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tests&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">82&lt;/span>&lt;span class="cl">&lt;span class="nx">addopts&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;-v --tb=short&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="與其他工具的比較">與其他工具的比較&lt;/h2>
&lt;h3 id="poetry-vs-pip">Poetry vs pip&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>操作&lt;/th>
 &lt;th>pip&lt;/th>
 &lt;th>Poetry&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>安裝相依性&lt;/td>
 &lt;td>&lt;code>pip install -r requirements.txt&lt;/code>&lt;/td>
 &lt;td>&lt;code>poetry install&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>新增相依性&lt;/td>
 &lt;td>手動編輯 requirements.txt&lt;/td>
 &lt;td>&lt;code>poetry add package&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>鎖定版本&lt;/td>
 &lt;td>&lt;code>pip freeze &amp;gt; requirements.txt&lt;/code>&lt;/td>
 &lt;td>自動更新 poetry.lock&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>建立環境&lt;/td>
 &lt;td>&lt;code>python -m venv .venv&lt;/code>&lt;/td>
 &lt;td>自動建立&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>執行命令&lt;/td>
 &lt;td>&lt;code>source .venv/bin/activate &amp;amp;&amp;amp; python&lt;/code>&lt;/td>
 &lt;td>&lt;code>poetry run python&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>建構套件&lt;/td>
 &lt;td>&lt;code>python -m build&lt;/code>&lt;/td>
 &lt;td>&lt;code>poetry build&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>發布套件&lt;/td>
 &lt;td>&lt;code>twine upload dist/*&lt;/code>&lt;/td>
 &lt;td>&lt;code>poetry publish&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="poetry-vs-setuptools">Poetry vs setuptools&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>面向&lt;/th>
 &lt;th>setuptools&lt;/th>
 &lt;th>Poetry&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>設定格式&lt;/td>
 &lt;td>pyproject.toml + 可能需要 setup.py&lt;/td>
 &lt;td>僅 pyproject.toml&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>相依性管理&lt;/td>
 &lt;td>需要額外工具&lt;/td>
 &lt;td>內建完整支援&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>環境管理&lt;/td>
 &lt;td>無&lt;/td>
 &lt;td>內建&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>學習曲線&lt;/td>
 &lt;td>較陡（歷史包袱）&lt;/td>
 &lt;td>較平緩&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>C 擴展支援&lt;/td>
 &lt;td>完整&lt;/td>
 &lt;td>不支援&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>生態系統&lt;/td>
 &lt;td>最廣泛&lt;/td>
 &lt;td>持續成長&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="poetry-vs-hatch">Poetry vs Hatch&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>面向&lt;/th>
 &lt;th>Hatch&lt;/th>
 &lt;th>Poetry&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>設計理念&lt;/td>
 &lt;td>PEP 標準優先&lt;/td>
 &lt;td>使用者體驗優先&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>相依性鎖定&lt;/td>
 &lt;td>無內建&lt;/td>
 &lt;td>核心功能&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>環境管理&lt;/td>
 &lt;td>多環境（類似 tox）&lt;/td>
 &lt;td>單一虛擬環境&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>腳本系統&lt;/td>
 &lt;td>完整&lt;/td>
 &lt;td>基本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>建構後端&lt;/td>
 &lt;td>hatchling&lt;/td>
 &lt;td>poetry-core&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>適用場景&lt;/td>
 &lt;td>開源函式庫&lt;/td>
 &lt;td>應用程式、內部工具&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="實用技巧">實用技巧&lt;/h2>
&lt;h3 id="技巧一善用-lock-檔案">技巧一：善用 Lock 檔案&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># poetry.lock 的重要性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c1"># - 記錄所有相依性的精確版本（包含間接相依性）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="c1"># - 確保團隊成員、CI/CD 使用相同版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># - 應該提交到版本控制&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="c1"># 根據 lock 檔案安裝（不更新）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">poetry install --no-update
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="c1"># 驗證 lock 檔案與 pyproject.toml 一致&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">poetry check --lock
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1"># 匯出為 requirements.txt（部署用）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">poetry &lt;span class="nb">export&lt;/span> -f requirements.txt -o requirements.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">poetry &lt;span class="nb">export&lt;/span> -f requirements.txt --with dev -o requirements-dev.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">poetry &lt;span class="nb">export&lt;/span> --without-hashes -o requirements.txt&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="技巧二善用相依性群組">技巧二：善用相依性群組&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c"># 開發相依性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dev&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">pytest&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^8.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="nx">ruff&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^0.4&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="c"># 可選群組（預設不安裝）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">docs&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">optional&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">docs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nx">mkdocs&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^1.5&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="c"># CI 專用群組&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ci&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="nx">optional&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ci&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="nx">pytest-cov&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^4.1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="nx">codecov&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^2.1&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 安裝特定群組&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">poetry install --with docs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">poetry install --with ci
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="c1"># CI 環境中的安裝&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">poetry install --only main,ci&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="技巧三善用-extras">技巧三：善用 Extras&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">optional-dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="c"># 功能性 extras&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="nx">yaml&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;pyyaml&amp;gt;=6.0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="nx">async&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;httpx&amp;gt;=0.24&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;aiofiles&amp;gt;=23.0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="c"># 完整安裝&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="nx">all&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;my-package[yaml,async]&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 使用者安裝方式&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">pip install my-package &lt;span class="c1"># 基本功能&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">pip install &lt;span class="s2">&amp;#34;my-package[yaml]&amp;#34;&lt;/span> &lt;span class="c1"># 包含 YAML 支援&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">pip install &lt;span class="s2">&amp;#34;my-package[all]&amp;#34;&lt;/span> &lt;span class="c1"># 所有功能&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="技巧四本地相依性和-git-相依性">技巧四：本地相依性和 Git 相依性&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="c"># 本地路徑相依性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="nx">my-local-lib&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">path&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;../my-local-lib&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">develop&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="c"># Git 相依性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="nx">my-git-lib&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">git&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://github.com/user/repo.git&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="nx">my-git-lib&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">git&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://github.com/user/repo.git&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">branch&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;develop&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">&lt;span class="nx">my-git-lib&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">git&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://github.com/user/repo.git&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">tag&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;v1.0.0&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">9&lt;/span>&lt;span class="cl">&lt;span class="nx">my-git-lib&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">git&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://github.com/user/repo.git&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">rev&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;abc123&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="技巧五平台特定相依性">技巧五：平台特定相依性&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="c"># 僅 Windows&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="nx">pywin32&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^306&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">markers&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;sys_platform == &amp;#39;win32&amp;#39;&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="c"># 僅 Linux&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="nx">uvloop&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^0.19&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">markers&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;sys_platform == &amp;#39;linux&amp;#39;&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">&lt;span class="c"># Python 版本限制&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">9&lt;/span>&lt;span class="cl">&lt;span class="nx">typing-extensions&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^4.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">python&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;lt;3.11&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="技巧六poetry-腳本">技巧六：Poetry 腳本&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">scripts&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="nx">my-cli&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my_package.cli:main&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="nx">my-tool&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my_package.tools:run&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># src/my_package/cli.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">click&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="nd">@click.command&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="nd">@click.option&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;--name&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">default&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;World&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">help&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;Name to greet&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Greet someone.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl"> &lt;span class="n">click&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">echo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Hello, &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> &lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 安裝後即可使用&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">my-cli --name Python
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="c1"># 輸出：Hello, Python!&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="常見問題與解決">常見問題與解決&lt;/h2>
&lt;h3 id="問題一相依性解析衝突">問題一：相依性解析衝突&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 錯誤訊息&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">SolverProblemError: ...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 解決方法&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="c1"># 1. 檢視衝突詳情&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">poetry show --tree
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="c1"># 2. 放寬版本限制&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">poetry add &lt;span class="s2">&amp;#34;package&amp;gt;=1.0,&amp;lt;3.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="c1"># 3. 強制更新 lock 檔案&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">poetry lock --no-update&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="問題二虛擬環境問題">問題二：虛擬環境問題&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 重建虛擬環境&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">poetry env remove --all
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">poetry install
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="c1"># 指定 Python 版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">poetry env use /usr/bin/python3.11&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="問題三cicd-快取">問題三：CI/CD 快取&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c"># GitHub Actions 範例&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Install Poetry&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">snok/install-poetry@v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">virtualenvs-create&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">virtualenvs-in-project&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Load cached venv&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/cache@v4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">.venv&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">key&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">venv-${{ runner.os }}-${{ hashFiles(&amp;#39;**/poetry.lock&amp;#39;) }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Install dependencies&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">if&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">steps.cache.outputs.cache-hit != &amp;#39;true&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">poetry install --no-interaction&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="設計權衡">設計權衡&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>面向&lt;/th>
 &lt;th>優點&lt;/th>
 &lt;th>缺點&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>相依性鎖定&lt;/strong>&lt;/td>
 &lt;td>環境可重現、團隊一致&lt;/td>
 &lt;td>lock 檔案衝突、更新需謹慎&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>一體化工具&lt;/strong>&lt;/td>
 &lt;td>學習成本低、工作流統一&lt;/td>
 &lt;td>與其他工具整合需調整&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>虛擬環境整合&lt;/strong>&lt;/td>
 &lt;td>自動管理、不易混淆&lt;/td>
 &lt;td>自訂環境位置需設定&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>建構與發布&lt;/strong>&lt;/td>
 &lt;td>流程簡化&lt;/td>
 &lt;td>不支援 C 擴展&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="練習">練習&lt;/h2>
&lt;h3 id="基礎練習建立-poetry-專案">基礎練習：建立 Poetry 專案&lt;/h3>
&lt;p>&lt;strong>目標&lt;/strong>：使用 Poetry 建立一個簡單的專案&lt;/p></description><content:encoded><![CDATA[<p>本案例展示如何使用 Poetry 管理現代 Python 專案的完整生命週期，從專案建立到套件發布。</p>
<h2 id="先備知識">先備知識</h2>
<ul>
<li><a href="/blog/python-advanced/07-packaging/build-systems/" data-link-title="6.2 建構系統比較" data-link-desc="比較 setuptools、Poetry、Hatch 等建構系統">建構系統比較</a></li>
<li>Python 虛擬環境基礎</li>
<li>套件相依性概念</li>
</ul>
<h2 id="問題背景">問題背景</h2>
<h3 id="現代專案的挑戰">現代專案的挑戰</h3>
<p>傳統的 Python 專案管理面臨以下問題：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">傳統工作流程的痛點：
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── 相依性管理
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">│   ├── requirements.txt 無法鎖定間接相依性
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">│   ├── pip freeze 產生的版本可能過於嚴格
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">│   └── 開發與生產環境相依性混在一起
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">├── 虛擬環境
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">│   ├── 需要手動建立和管理
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">│   ├── 不同專案的環境容易混淆
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">│   └── 缺乏與專案的關聯性
</span></span><span class="line"><span class="ln">10</span><span class="cl">├── 建構與發布
</span></span><span class="line"><span class="ln">11</span><span class="cl">│   ├── setup.py 設定複雜
</span></span><span class="line"><span class="ln">12</span><span class="cl">│   ├── 發布流程需要多個工具
</span></span><span class="line"><span class="ln">13</span><span class="cl">│   └── 版本管理不一致
</span></span><span class="line"><span class="ln">14</span><span class="cl">└── 團隊協作
</span></span><span class="line"><span class="ln">15</span><span class="cl">    ├── 環境難以重現
</span></span><span class="line"><span class="ln">16</span><span class="cl">    ├── 「在我電腦上可以跑」問題
</span></span><span class="line"><span class="ln">17</span><span class="cl">    └── 新成員上手困難</span></span></code></pre></div><h3 id="為什麼選擇-poetry">為什麼選擇 Poetry？</h3>
<table>
  <thead>
      <tr>
          <th>特性</th>
          <th>pip + venv</th>
          <th>Poetry</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>相依性鎖定</td>
          <td>手動（pip freeze）</td>
          <td>自動（poetry.lock）</td>
      </tr>
      <tr>
          <td>間接相依性追蹤</td>
          <td>無</td>
          <td>完整追蹤</td>
      </tr>
      <tr>
          <td>虛擬環境管理</td>
          <td>手動</td>
          <td>自動整合</td>
      </tr>
      <tr>
          <td>建構系統</td>
          <td>需要額外工具</td>
          <td>內建</td>
      </tr>
      <tr>
          <td>發布流程</td>
          <td>需要 twine</td>
          <td>內建</td>
      </tr>
      <tr>
          <td>相依性群組</td>
          <td>無原生支援</td>
          <td>完整支援</td>
      </tr>
  </tbody>
</table>
<h2 id="解決方案">解決方案</h2>
<h3 id="安裝-poetry">安裝 Poetry</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 官方推薦的安裝方式（獨立安裝）</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">curl -sSL https://install.python-poetry.org <span class="p">|</span> python3 -
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># 或使用 pipx（推薦用於 CLI 工具）</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">pipx install poetry
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"># 確認安裝</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">poetry --version</span></span></code></pre></div><h4 id="設定-poetry">設定 Poetry</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 在專案目錄中建立虛擬環境（推薦）</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">poetry config virtualenvs.in-project <span class="nb">true</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># 查看所有設定</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">poetry config --list</span></span></code></pre></div><h3 id="工作流一建立新專案">工作流一：建立新專案</h3>
<h4 id="使用-poetry-new完整專案結構">使用 poetry new（完整專案結構）</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 建立新專案</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">poetry new my-awesome-lib
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 產生的目錄結構</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">my-awesome-lib/
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">├── pyproject.toml
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">├── README.md
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">├── my_awesome_lib/
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">│   └── __init__.py
</span></span><span class="line"><span class="ln">10</span><span class="cl">└── tests/
</span></span><span class="line"><span class="ln">11</span><span class="cl">    └── __init__.py</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 使用 src layout（推薦用於函式庫）</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">poetry new --src my-awesome-lib
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 產生的目錄結構</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">my-awesome-lib/
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">├── pyproject.toml
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">├── README.md
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">├── src/
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">│   └── my_awesome_lib/
</span></span><span class="line"><span class="ln">10</span><span class="cl">│       └── __init__.py
</span></span><span class="line"><span class="ln">11</span><span class="cl">└── tests/
</span></span><span class="line"><span class="ln">12</span><span class="cl">    └── __init__.py</span></span></code></pre></div><h4 id="使用-poetry-init現有專案">使用 poetry init（現有專案）</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 在現有目錄初始化</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nb">cd</span> existing-project
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">poetry init
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"># 互動式問答</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1"># - Package name</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># - Version</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"># - Description</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># - Author</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># - License</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"># - Python version</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"># - Dependencies</span></span></span></code></pre></div><h5 id="互動式初始化範例">互動式初始化範例</h5>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">This command will guide you through creating your pyproject.toml config.
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">Package name [existing-project]:  my-package
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">Version [0.1.0]:  1.0.0
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">Description []:  A useful Python package
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">Author [Your Name &lt;you@example.com&gt;, n to skip]:
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">License []:  MIT
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">Compatible Python versions [^3.10]:  ^3.10
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl">Would you like to define your main dependencies interactively? (yes/no) [yes]
</span></span><span class="line"><span class="ln">11</span><span class="cl">Search for package to add (or leave blank to continue): requests
</span></span><span class="line"><span class="ln">12</span><span class="cl">...</span></span></code></pre></div><h3 id="工作流二管理相依性">工作流二：管理相依性</h3>
<h4 id="新增相依性">新增相依性</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 新增生產相依性</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">poetry add requests
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">poetry add <span class="s2">&#34;httpx&gt;=0.24&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"># 新增開發相依性</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">poetry add pytest --group dev
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">poetry add ruff mypy --group dev
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># 新增文件相依性</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">poetry add mkdocs mkdocs-material --group docs
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"># 新增可選相依性（extras）</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">poetry add pyyaml --optional</span></span></code></pre></div><h5 id="pyprojecttoml-的變化">pyproject.toml 的變化</h5>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nx">python</span> <span class="p">=</span> <span class="s2">&#34;^3.10&#34;</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">requests</span> <span class="p">=</span> <span class="s2">&#34;^2.31.0&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nx">httpx</span> <span class="p">=</span> <span class="s2">&#34;&gt;=0.24&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">group</span><span class="p">.</span><span class="nx">dev</span><span class="p">.</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">pytest</span> <span class="p">=</span> <span class="s2">&#34;^8.0.0&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">ruff</span> <span class="p">=</span> <span class="s2">&#34;^0.4.0&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nx">mypy</span> <span class="p">=</span> <span class="s2">&#34;^1.10.0&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">group</span><span class="p">.</span><span class="nx">docs</span><span class="p">.</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nx">mkdocs</span> <span class="p">=</span> <span class="s2">&#34;^1.5.0&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nx">mkdocs-material</span> <span class="p">=</span> <span class="s2">&#34;^9.5.0&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">extras</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="nx">yaml</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;pyyaml&#34;</span><span class="p">]</span></span></span></code></pre></div><h4 id="移除相依性">移除相依性</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 移除生產相依性</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">poetry remove requests
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># 移除開發相依性</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">poetry remove pytest --group dev</span></span></code></pre></div><h4 id="更新相依性">更新相依性</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 更新所有相依性</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">poetry update
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 更新特定套件</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">poetry update requests
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># 檢視可更新的套件</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">poetry show --outdated
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># 檢視相依性樹</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">poetry show --tree</span></span></code></pre></div><h5 id="相依性樹範例輸出">相依性樹範例輸出</h5>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">requests 2.31.0 Python HTTP for Humans.
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── certifi &gt;=2017.4.17
</span></span><span class="line"><span class="ln">3</span><span class="cl">├── charset-normalizer &gt;=2,&lt;4
</span></span><span class="line"><span class="ln">4</span><span class="cl">├── idna &gt;=2.5,&lt;4
</span></span><span class="line"><span class="ln">5</span><span class="cl">└── urllib3 &gt;=1.21.1,&lt;3</span></span></code></pre></div><h3 id="工作流三虛擬環境管理">工作流三：虛擬環境管理</h3>
<h4 id="自動環境管理">自動環境管理</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 安裝所有相依性（自動建立虛擬環境）</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">poetry install
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 僅安裝生產相依性</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">poetry install --only main
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># 安裝包含特定群組</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">poetry install --with dev,docs
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># 排除特定群組</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">poetry install --without docs
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1"># 安裝 extras</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">poetry install --extras yaml
</span></span><span class="line"><span class="ln">15</span><span class="cl">poetry install --all-extras</span></span></code></pre></div><h4 id="環境操作">環境操作</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 進入虛擬環境 shell</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">poetry shell
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 在虛擬環境中執行命令（不進入 shell）</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">poetry run python script.py
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">poetry run pytest
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">poetry run python -c <span class="s2">&#34;import my_package; print(my_package.__version__)&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># 顯示環境資訊</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">poetry env info
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"># 顯示環境路徑</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">poetry env info --path
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c1"># 列出所有環境</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">poetry env list
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"># 切換 Python 版本</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">poetry env use python3.11
</span></span><span class="line"><span class="ln">20</span><span class="cl">poetry env use 3.12
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="c1"># 刪除環境</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">poetry env remove python3.11
</span></span><span class="line"><span class="ln">24</span><span class="cl">poetry env remove --all</span></span></code></pre></div><h5 id="環境資訊範例輸出">環境資訊範例輸出</h5>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">Virtualenv
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">Python:         3.11.6
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">Implementation: CPython
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">Path:           /path/to/project/.venv
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">Executable:     /path/to/project/.venv/bin/python
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">Valid:          True
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">Base
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">Platform:   darwin
</span></span><span class="line"><span class="ln">10</span><span class="cl">OS:         posix
</span></span><span class="line"><span class="ln">11</span><span class="cl">Python:     3.11.6
</span></span><span class="line"><span class="ln">12</span><span class="cl">Path:       /opt/homebrew/Cellar/python@3.11/3.11.6/Frameworks/Python.framework/Versions/3.11
</span></span><span class="line"><span class="ln">13</span><span class="cl">Executable: /opt/homebrew/Cellar/python@3.11/3.11.6/Frameworks/Python.framework/Versions/3.11/bin/python3.11</span></span></code></pre></div><h3 id="工作流四建構與發布">工作流四：建構與發布</h3>
<h4 id="建構套件">建構套件</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 建構 sdist 和 wheel</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">poetry build
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 僅建構 wheel</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">poetry build --format wheel
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># 建構結果</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">dist/
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">├── my_package-1.0.0-py3-none-any.whl
</span></span><span class="line"><span class="ln">10</span><span class="cl">└── my_package-1.0.0.tar.gz</span></span></code></pre></div><h4 id="發布到-pypi">發布到 PyPI</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 設定 PyPI token</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">poetry config pypi-token.pypi pypi-XXXXXXXXXXXX
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 發布到 PyPI</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">poetry publish
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># 建構並發布（一步完成）</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">poetry publish --build
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># 發布到 TestPyPI</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">poetry config repositories.testpypi https://test.pypi.org/legacy/
</span></span><span class="line"><span class="ln">12</span><span class="cl">poetry config pypi-token.testpypi pypi-XXXXXXXXXXXX
</span></span><span class="line"><span class="ln">13</span><span class="cl">poetry publish --repository testpypi</span></span></code></pre></div><h5 id="版本管理">版本管理</h5>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 查看當前版本</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">poetry version
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 升級版本</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">poetry version patch   <span class="c1"># 1.0.0 -&gt; 1.0.1</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">poetry version minor   <span class="c1"># 1.0.0 -&gt; 1.1.0</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">poetry version major   <span class="c1"># 1.0.0 -&gt; 2.0.0</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># 設定特定版本</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">poetry version 2.0.0
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"># 預發布版本</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">poetry version prepatch  <span class="c1"># 1.0.0 -&gt; 1.0.1a0</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">poetry version preminor  <span class="c1"># 1.0.0 -&gt; 1.1.0a0</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">poetry version premajor  <span class="c1"># 1.0.0 -&gt; 2.0.0a0</span></span></span></code></pre></div><h3 id="完整-pyprojecttoml-範例">完整 pyproject.toml 範例</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">build-system</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nx">requires</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;poetry-core&gt;=2.0&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">build-backend</span> <span class="p">=</span> <span class="s2">&#34;poetry.core.masonry.api&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;my-awesome-lib&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;1.0.0&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">description</span> <span class="p">=</span> <span class="s2">&#34;A feature-rich Python library&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nx">readme</span> <span class="p">=</span> <span class="s2">&#34;README.md&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nx">license</span> <span class="p">=</span> <span class="s2">&#34;MIT&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">requires-python</span> <span class="p">=</span> <span class="s2">&#34;&gt;=3.10&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nx">authors</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="p">{</span> <span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;Your Name&#34;</span><span class="p">,</span> <span class="nx">email</span> <span class="p">=</span> <span class="s2">&#34;you@example.com&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="nx">keywords</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;python&#34;</span><span class="p">,</span> <span class="s2">&#34;library&#34;</span><span class="p">,</span> <span class="s2">&#34;utilities&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="nx">classifiers</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="s2">&#34;Development Status :: 4 - Beta&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="s2">&#34;Intended Audience :: Developers&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="s2">&#34;License :: OSI Approved :: MIT License&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="s2">&#34;Operating System :: OS Independent&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: 3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: 3.10&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: 3.11&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: 3.12&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="s2">&#34;Programming Language :: Python :: 3.13&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">    <span class="s2">&#34;Typing :: Typed&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">urls</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="nx">Homepage</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/yourname/my-awesome-lib&#34;</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="nx">Documentation</span> <span class="p">=</span> <span class="s2">&#34;https://my-awesome-lib.readthedocs.io&#34;</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="nx">Repository</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/yourname/my-awesome-lib.git&#34;</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="nx">Changelog</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/yourname/my-awesome-lib/blob/main/CHANGELOG.md&#34;</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">
</span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">scripts</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="nx">my-cli</span> <span class="p">=</span> <span class="s2">&#34;my_awesome_lib.cli:main&#34;</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">
</span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">optional-dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="nx">yaml</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;pyyaml&gt;=6.0&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="nx">all</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;my-awesome-lib[yaml]&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">
</span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="c"># ===== Poetry 特定設定 =====</span>
</span></span><span class="line"><span class="ln">43</span><span class="cl">
</span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="nx">packages</span> <span class="p">=</span> <span class="p">[{</span> <span class="nx">include</span> <span class="p">=</span> <span class="s2">&#34;my_awesome_lib&#34;</span><span class="p">,</span> <span class="nx">from</span> <span class="p">=</span> <span class="s2">&#34;src&#34;</span> <span class="p">}]</span>
</span></span><span class="line"><span class="ln">46</span><span class="cl">
</span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="nx">python</span> <span class="p">=</span> <span class="s2">&#34;^3.10&#34;</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="nx">requests</span> <span class="p">=</span> <span class="s2">&#34;^2.31&#34;</span>
</span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="nx">click</span> <span class="p">=</span> <span class="s2">&#34;^8.1&#34;</span>
</span></span><span class="line"><span class="ln">51</span><span class="cl">
</span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">group</span><span class="p">.</span><span class="nx">dev</span><span class="p">.</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="nx">pytest</span> <span class="p">=</span> <span class="s2">&#34;^8.0&#34;</span>
</span></span><span class="line"><span class="ln">54</span><span class="cl"><span class="nx">pytest-cov</span> <span class="p">=</span> <span class="s2">&#34;^4.1&#34;</span>
</span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="nx">pytest-asyncio</span> <span class="p">=</span> <span class="s2">&#34;^0.23&#34;</span>
</span></span><span class="line"><span class="ln">56</span><span class="cl"><span class="nx">mypy</span> <span class="p">=</span> <span class="s2">&#34;^1.10&#34;</span>
</span></span><span class="line"><span class="ln">57</span><span class="cl"><span class="nx">ruff</span> <span class="p">=</span> <span class="s2">&#34;^0.4&#34;</span>
</span></span><span class="line"><span class="ln">58</span><span class="cl">
</span></span><span class="line"><span class="ln">59</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">group</span><span class="p">.</span><span class="nx">docs</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">60</span><span class="cl"><span class="nx">optional</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln">61</span><span class="cl">
</span></span><span class="line"><span class="ln">62</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">group</span><span class="p">.</span><span class="nx">docs</span><span class="p">.</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">63</span><span class="cl"><span class="nx">mkdocs</span> <span class="p">=</span> <span class="s2">&#34;^1.5&#34;</span>
</span></span><span class="line"><span class="ln">64</span><span class="cl"><span class="nx">mkdocs-material</span> <span class="p">=</span> <span class="s2">&#34;^9.5&#34;</span>
</span></span><span class="line"><span class="ln">65</span><span class="cl">
</span></span><span class="line"><span class="ln">66</span><span class="cl"><span class="c"># ===== 工具設定 =====</span>
</span></span><span class="line"><span class="ln">67</span><span class="cl">
</span></span><span class="line"><span class="ln">68</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">ruff</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">69</span><span class="cl"><span class="nx">src</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;src&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">70</span><span class="cl"><span class="nx">line-length</span> <span class="p">=</span> <span class="mi">88</span>
</span></span><span class="line"><span class="ln">71</span><span class="cl"><span class="nx">target-version</span> <span class="p">=</span> <span class="s2">&#34;py310&#34;</span>
</span></span><span class="line"><span class="ln">72</span><span class="cl">
</span></span><span class="line"><span class="ln">73</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">ruff</span><span class="p">.</span><span class="nx">lint</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">74</span><span class="cl"><span class="nx">select</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;E&#34;</span><span class="p">,</span> <span class="s2">&#34;W&#34;</span><span class="p">,</span> <span class="s2">&#34;F&#34;</span><span class="p">,</span> <span class="s2">&#34;I&#34;</span><span class="p">,</span> <span class="s2">&#34;B&#34;</span><span class="p">,</span> <span class="s2">&#34;C4&#34;</span><span class="p">,</span> <span class="s2">&#34;UP&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">75</span><span class="cl">
</span></span><span class="line"><span class="ln">76</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">mypy</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">77</span><span class="cl"><span class="nx">python_version</span> <span class="p">=</span> <span class="s2">&#34;3.10&#34;</span>
</span></span><span class="line"><span class="ln">78</span><span class="cl"><span class="nx">strict</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln">79</span><span class="cl">
</span></span><span class="line"><span class="ln">80</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">pytest</span><span class="p">.</span><span class="nx">ini_options</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">81</span><span class="cl"><span class="nx">testpaths</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;tests&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">82</span><span class="cl"><span class="nx">addopts</span> <span class="p">=</span> <span class="s2">&#34;-v --tb=short&#34;</span></span></span></code></pre></div><h2 id="與其他工具的比較">與其他工具的比較</h2>
<h3 id="poetry-vs-pip">Poetry vs pip</h3>
<table>
  <thead>
      <tr>
          <th>操作</th>
          <th>pip</th>
          <th>Poetry</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>安裝相依性</td>
          <td><code>pip install -r requirements.txt</code></td>
          <td><code>poetry install</code></td>
      </tr>
      <tr>
          <td>新增相依性</td>
          <td>手動編輯 requirements.txt</td>
          <td><code>poetry add package</code></td>
      </tr>
      <tr>
          <td>鎖定版本</td>
          <td><code>pip freeze &gt; requirements.txt</code></td>
          <td>自動更新 poetry.lock</td>
      </tr>
      <tr>
          <td>建立環境</td>
          <td><code>python -m venv .venv</code></td>
          <td>自動建立</td>
      </tr>
      <tr>
          <td>執行命令</td>
          <td><code>source .venv/bin/activate &amp;&amp; python</code></td>
          <td><code>poetry run python</code></td>
      </tr>
      <tr>
          <td>建構套件</td>
          <td><code>python -m build</code></td>
          <td><code>poetry build</code></td>
      </tr>
      <tr>
          <td>發布套件</td>
          <td><code>twine upload dist/*</code></td>
          <td><code>poetry publish</code></td>
      </tr>
  </tbody>
</table>
<h3 id="poetry-vs-setuptools">Poetry vs setuptools</h3>
<table>
  <thead>
      <tr>
          <th>面向</th>
          <th>setuptools</th>
          <th>Poetry</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>設定格式</td>
          <td>pyproject.toml + 可能需要 setup.py</td>
          <td>僅 pyproject.toml</td>
      </tr>
      <tr>
          <td>相依性管理</td>
          <td>需要額外工具</td>
          <td>內建完整支援</td>
      </tr>
      <tr>
          <td>環境管理</td>
          <td>無</td>
          <td>內建</td>
      </tr>
      <tr>
          <td>學習曲線</td>
          <td>較陡（歷史包袱）</td>
          <td>較平緩</td>
      </tr>
      <tr>
          <td>C 擴展支援</td>
          <td>完整</td>
          <td>不支援</td>
      </tr>
      <tr>
          <td>生態系統</td>
          <td>最廣泛</td>
          <td>持續成長</td>
      </tr>
  </tbody>
</table>
<h3 id="poetry-vs-hatch">Poetry vs Hatch</h3>
<table>
  <thead>
      <tr>
          <th>面向</th>
          <th>Hatch</th>
          <th>Poetry</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>設計理念</td>
          <td>PEP 標準優先</td>
          <td>使用者體驗優先</td>
      </tr>
      <tr>
          <td>相依性鎖定</td>
          <td>無內建</td>
          <td>核心功能</td>
      </tr>
      <tr>
          <td>環境管理</td>
          <td>多環境（類似 tox）</td>
          <td>單一虛擬環境</td>
      </tr>
      <tr>
          <td>腳本系統</td>
          <td>完整</td>
          <td>基本</td>
      </tr>
      <tr>
          <td>建構後端</td>
          <td>hatchling</td>
          <td>poetry-core</td>
      </tr>
      <tr>
          <td>適用場景</td>
          <td>開源函式庫</td>
          <td>應用程式、內部工具</td>
      </tr>
  </tbody>
</table>
<h2 id="實用技巧">實用技巧</h2>
<h3 id="技巧一善用-lock-檔案">技巧一：善用 Lock 檔案</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># poetry.lock 的重要性</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"># - 記錄所有相依性的精確版本（包含間接相依性）</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="c1"># - 確保團隊成員、CI/CD 使用相同版本</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># - 應該提交到版本控制</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1"># 根據 lock 檔案安裝（不更新）</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">poetry install --no-update
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># 驗證 lock 檔案與 pyproject.toml 一致</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">poetry check --lock
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"># 匯出為 requirements.txt（部署用）</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">poetry <span class="nb">export</span> -f requirements.txt -o requirements.txt
</span></span><span class="line"><span class="ln">14</span><span class="cl">poetry <span class="nb">export</span> -f requirements.txt --with dev -o requirements-dev.txt
</span></span><span class="line"><span class="ln">15</span><span class="cl">poetry <span class="nb">export</span> --without-hashes -o requirements.txt</span></span></code></pre></div><h3 id="技巧二善用相依性群組">技巧二：善用相依性群組</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c"># 開發相依性</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">group</span><span class="p">.</span><span class="nx">dev</span><span class="p">.</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">pytest</span> <span class="p">=</span> <span class="s2">&#34;^8.0&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nx">ruff</span> <span class="p">=</span> <span class="s2">&#34;^0.4&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c"># 可選群組（預設不安裝）</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">group</span><span class="p">.</span><span class="nx">docs</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">optional</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">group</span><span class="p">.</span><span class="nx">docs</span><span class="p">.</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">mkdocs</span> <span class="p">=</span> <span class="s2">&#34;^1.5&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c"># CI 專用群組</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">group</span><span class="p">.</span><span class="nx">ci</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="nx">optional</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">group</span><span class="p">.</span><span class="nx">ci</span><span class="p">.</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="nx">pytest-cov</span> <span class="p">=</span> <span class="s2">&#34;^4.1&#34;</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="nx">codecov</span> <span class="p">=</span> <span class="s2">&#34;^2.1&#34;</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 安裝特定群組</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">poetry install --with docs
</span></span><span class="line"><span class="ln">3</span><span class="cl">poetry install --with ci
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"># CI 環境中的安裝</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">poetry install --only main,ci</span></span></code></pre></div><h3 id="技巧三善用-extras">技巧三：善用 Extras</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">optional-dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c"># 功能性 extras</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nx">yaml</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;pyyaml&gt;=6.0&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nx">async</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;httpx&gt;=0.24&#34;</span><span class="p">,</span> <span class="s2">&#34;aiofiles&gt;=23.0&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c"># 完整安裝</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="nx">all</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;my-package[yaml,async]&#34;</span><span class="p">]</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 使用者安裝方式</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">pip install my-package           <span class="c1"># 基本功能</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">pip install <span class="s2">&#34;my-package[yaml]&#34;</span>   <span class="c1"># 包含 YAML 支援</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">pip install <span class="s2">&#34;my-package[all]&#34;</span>    <span class="c1"># 所有功能</span></span></span></code></pre></div><h3 id="技巧四本地相依性和-git-相依性">技巧四：本地相依性和 Git 相依性</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c"># 本地路徑相依性</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nx">my-local-lib</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">path</span> <span class="p">=</span> <span class="s2">&#34;../my-local-lib&#34;</span><span class="p">,</span> <span class="nx">develop</span> <span class="p">=</span> <span class="kc">true</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c"># Git 相依性</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nx">my-git-lib</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">git</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/user/repo.git&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="nx">my-git-lib</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">git</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/user/repo.git&#34;</span><span class="p">,</span> <span class="nx">branch</span> <span class="p">=</span> <span class="s2">&#34;develop&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="nx">my-git-lib</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">git</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/user/repo.git&#34;</span><span class="p">,</span> <span class="nx">tag</span> <span class="p">=</span> <span class="s2">&#34;v1.0.0&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="nx">my-git-lib</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">git</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/user/repo.git&#34;</span><span class="p">,</span> <span class="nx">rev</span> <span class="p">=</span> <span class="s2">&#34;abc123&#34;</span> <span class="p">}</span></span></span></code></pre></div><h3 id="技巧五平台特定相依性">技巧五：平台特定相依性</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c"># 僅 Windows</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nx">pywin32</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;^306&#34;</span><span class="p">,</span> <span class="nx">markers</span> <span class="p">=</span> <span class="s2">&#34;sys_platform == &#39;win32&#39;&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c"># 僅 Linux</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nx">uvloop</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;^0.19&#34;</span><span class="p">,</span> <span class="nx">markers</span> <span class="p">=</span> <span class="s2">&#34;sys_platform == &#39;linux&#39;&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="c"># Python 版本限制</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="nx">typing-extensions</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;^4.0&#34;</span><span class="p">,</span> <span class="nx">python</span> <span class="p">=</span> <span class="s2">&#34;&lt;3.11&#34;</span> <span class="p">}</span></span></span></code></pre></div><h3 id="技巧六poetry-腳本">技巧六：Poetry 腳本</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">scripts</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nx">my-cli</span> <span class="p">=</span> <span class="s2">&#34;my_package.cli:main&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nx">my-tool</span> <span class="p">=</span> <span class="s2">&#34;my_package.tools:run&#34;</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># src/my_package/cli.py</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kn">import</span> <span class="nn">click</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nd">@click.command</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="nd">@click.option</span><span class="p">(</span><span class="s2">&#34;--name&#34;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s2">&#34;World&#34;</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&#34;Name to greet&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="s2">&#34;&#34;&#34;Greet someone.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Hello, </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="n">main</span><span class="p">()</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 安裝後即可使用</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">my-cli --name Python
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"># 輸出：Hello, Python!</span></span></span></code></pre></div><h2 id="常見問題與解決">常見問題與解決</h2>
<h3 id="問題一相依性解析衝突">問題一：相依性解析衝突</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 錯誤訊息</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">SolverProblemError: ...
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 解決方法</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"># 1. 檢視衝突詳情</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">poetry show --tree
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"># 2. 放寬版本限制</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">poetry add <span class="s2">&#34;package&gt;=1.0,&lt;3.0&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"># 3. 強制更新 lock 檔案</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">poetry lock --no-update</span></span></code></pre></div><h3 id="問題二虛擬環境問題">問題二：虛擬環境問題</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 重建虛擬環境</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">poetry env remove --all
</span></span><span class="line"><span class="ln">3</span><span class="cl">poetry install
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"># 指定 Python 版本</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">poetry env use /usr/bin/python3.11</span></span></code></pre></div><h3 id="問題三cicd-快取">問題三：CI/CD 快取</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c"># GitHub Actions 範例</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Install Poetry</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">  </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">snok/install-poetry@v1</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">  </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="nt">virtualenvs-create</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="nt">virtualenvs-in-project</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Load cached venv</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">  </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/cache@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">  </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">.venv</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="nt">key</span><span class="p">:</span><span class="w"> </span><span class="l">venv-${{ runner.os }}-${{ hashFiles(&#39;**/poetry.lock&#39;) }}</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Install dependencies</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">  </span><span class="nt">if</span><span class="p">:</span><span class="w"> </span><span class="l">steps.cache.outputs.cache-hit != &#39;true&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">  </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">poetry install --no-interaction</span></span></span></code></pre></div><h2 id="設計權衡">設計權衡</h2>
<table>
  <thead>
      <tr>
          <th>面向</th>
          <th>優點</th>
          <th>缺點</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>相依性鎖定</strong></td>
          <td>環境可重現、團隊一致</td>
          <td>lock 檔案衝突、更新需謹慎</td>
      </tr>
      <tr>
          <td><strong>一體化工具</strong></td>
          <td>學習成本低、工作流統一</td>
          <td>與其他工具整合需調整</td>
      </tr>
      <tr>
          <td><strong>虛擬環境整合</strong></td>
          <td>自動管理、不易混淆</td>
          <td>自訂環境位置需設定</td>
      </tr>
      <tr>
          <td><strong>建構與發布</strong></td>
          <td>流程簡化</td>
          <td>不支援 C 擴展</td>
      </tr>
  </tbody>
</table>
<h2 id="練習">練習</h2>
<h3 id="基礎練習建立-poetry-專案">基礎練習：建立 Poetry 專案</h3>
<p><strong>目標</strong>：使用 Poetry 建立一個簡單的專案</p>
<ol>
<li>使用 <code>poetry new --src my-utils</code> 建立專案</li>
<li>新增 <code>requests</code> 作為生產相依性</li>
<li>新增 <code>pytest</code> 和 <code>ruff</code> 作為開發相依性</li>
<li>執行 <code>poetry install</code> 並驗證環境</li>
</ol>
<h3 id="進階練習設定相依性群組">進階練習：設定相依性群組</h3>
<p><strong>目標</strong>：建立完整的相依性管理結構</p>
<ol>
<li>建立 <code>dev</code>、<code>docs</code>、<code>ci</code> 三個群組</li>
<li>將 <code>docs</code> 和 <code>ci</code> 設為可選群組</li>
<li>練習使用 <code>--with</code> 和 <code>--without</code> 選項</li>
</ol>
<h3 id="挑戰題完整發布流程">挑戰題：完整發布流程</h3>
<p><strong>目標</strong>：將專案發布到 TestPyPI</p>
<ol>
<li>設定 TestPyPI repository</li>
<li>使用 <code>poetry version</code> 管理版本</li>
<li>執行 <code>poetry build</code> 建構套件</li>
<li>執行 <code>poetry publish --repository testpypi</code> 發布</li>
</ol>
<h2 id="延伸閱讀">延伸閱讀</h2>
<ul>
<li><a href="https://python-poetry.org/docs/">Poetry 官方文件</a></li>
<li><a href="https://python-poetry.org/docs/cli/">Poetry CLI 參考</a></li>
<li><a href="https://peps.python.org/pep-0621/">pyproject.toml 規範 (PEP 621)</a></li>
<li><a href="https://packaging.python.org/">Python 打包使用者指南</a></li>
</ul>
<hr>
<p>返回：<a href="/blog/python-advanced/07-packaging/case-studies/" data-link-title="案例研究" data-link-desc="基於 .claude/lib 實際程式碼的打包發布案例">案例研究</a></p>
]]></content:encoded></item><item><title>案例：使用 Hatch 完整工作流</title><link>https://tarrragon.github.io/blog/python-advanced/07-packaging/case-studies/hatch-workflow/</link><pubDate>Wed, 21 Jan 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/python-advanced/07-packaging/case-studies/hatch-workflow/</guid><description>&lt;p>本案例展示如何使用 Hatch 這個 PyPA 推薦的現代 Python 專案管理工具，完成從專案建立到發布的完整流程。&lt;/p>
&lt;h2 id="先備知識">先備知識&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/python-advanced/07-packaging/build-systems/" data-link-title="6.2 建構系統比較" data-link-desc="比較 setuptools、Poetry、Hatch 等建構系統">6.2 建構系統比較&lt;/a>&lt;/li>
&lt;li>Python 虛擬環境基礎&lt;/li>
&lt;li>基本的命令列操作&lt;/li>
&lt;/ul>
&lt;h2 id="問題背景">問題背景&lt;/h2>
&lt;h3 id="hatch-是什麼">Hatch 是什麼？&lt;/h3>
&lt;p>Hatch 是由 PyPA（Python Packaging Authority）成員開發維護的現代 Python 專案管理工具，整合了：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">Hatch 功能整合：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">├── 專案腳手架（hatch new）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">├── 環境管理（類似 tox + virtualenv）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">├── 版本管理（自動更新版本號）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">├── 建構系統（hatchling）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">└── 發布工具（hatch publish）&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="為什麼選擇-hatch">為什麼選擇 Hatch？&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>優勢&lt;/th>
 &lt;th>說明&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>標準優先&lt;/strong>&lt;/td>
 &lt;td>完全遵循 PEP 517/518/621 標準&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>一站式工具&lt;/strong>&lt;/td>
 &lt;td>不需要額外安裝 tox、virtualenv、bump2version&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>快速建構&lt;/strong>&lt;/td>
 &lt;td>hatchling 建構速度優於 setuptools&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>環境矩陣&lt;/strong>&lt;/td>
 &lt;td>內建多 Python 版本測試支援&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>腳本系統&lt;/strong>&lt;/td>
 &lt;td>定義可重用的專案腳本&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="完整工作流">完整工作流&lt;/h2>
&lt;h3 id="第一步安裝-hatch">第一步：安裝 Hatch&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 使用 pip 安裝&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">pip install hatch
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 或使用 pipx（推薦，隔離安裝）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">pipx install hatch
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 驗證安裝&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">hatch --version&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="第二步建立新專案">第二步：建立新專案&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 建立新專案&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">hatch new my-awesome-lib
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 互動式建立（可自訂選項）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">hatch new my-awesome-lib --init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 建立應用程式專案（非函式庫）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">hatch new --cli my-cli-app&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="預設專案結構">預設專案結構&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">my-awesome-lib/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">├── src/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">│ └── my_awesome_lib/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">│ ├── __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">│ └── __about__.py # 版本資訊
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">├── tests/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">│ └── __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">├── pyproject.toml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">├── README.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">└── LICENSE.txt&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="生成的-pyprojecttoml">生成的 pyproject.toml&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">build-system&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="nx">requires&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;hatchling&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">build-backend&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;hatchling.build&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my-awesome-lib&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="nx">dynamic&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;version&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">description&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="nx">readme&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;README.md&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="nx">requires-python&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;gt;=3.8&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nx">license&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;MIT&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="nx">keywords&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="nx">authors&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl"> &lt;span class="p">{&lt;/span> &lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Your Name&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">email&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;you@example.com&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="nx">classifiers&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Development Status :: 4 - Beta&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: 3.8&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: 3.9&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: 3.10&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: 3.11&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;Programming Language :: Python :: 3.12&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl">&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">urls&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl">&lt;span class="nx">Documentation&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://github.com/yourname/my-awesome-lib#readme&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl">&lt;span class="nx">Issues&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://github.com/yourname/my-awesome-lib/issues&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl">&lt;span class="nx">Source&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://github.com/yourname/my-awesome-lib&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">version&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl">&lt;span class="nx">path&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;src/my_awesome_lib/__about__.py&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="第三步環境管理hatch-env">第三步：環境管理（hatch env）&lt;/h3>
&lt;h4 id="定義環境">定義環境&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c"># pyproject.toml&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="c"># 預設環境&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">default&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;pytest&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;pytest-cov&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">default&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">scripts&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nx">test&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;pytest {args:tests}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="nx">test-cov&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;pytest --cov=my_awesome_lib --cov-report=term-missing {args:tests}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="c"># Lint 環境&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">lint&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;ruff&amp;gt;=0.4&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;mypy&amp;gt;=1.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">lint&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">scripts&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">&lt;span class="nx">check&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;ruff check src tests&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;ruff format --check src tests&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl">&lt;span class="nx">fix&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;ruff check --fix src tests&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;ruff format src tests&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl">&lt;span class="nx">typing&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;mypy src&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl">&lt;span class="nx">all&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;check&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;typing&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl">&lt;span class="c"># 文件環境&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">34&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">docs&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">35&lt;/span>&lt;span class="cl">&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">36&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;mkdocs&amp;gt;=1.5&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">37&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;mkdocs-material&amp;gt;=9.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">38&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">39&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">40&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">docs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">scripts&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">41&lt;/span>&lt;span class="cl">&lt;span class="nx">build&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;mkdocs build&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">42&lt;/span>&lt;span class="cl">&lt;span class="nx">serve&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;mkdocs serve&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="使用環境">使用環境&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 顯示所有環境&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">hatch env show
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 執行預設環境的腳本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">hatch run &lt;span class="nb">test&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">hatch run test-cov
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="c1"># 執行特定環境的腳本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">hatch run lint:check
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">hatch run lint:fix
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">hatch run lint:typing
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="c1"># 進入環境 shell&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">hatch shell
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="c1"># 進入特定環境&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">hatch shell lint
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="c1"># 移除環境&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">hatch env remove
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">hatch env remove lint
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">&lt;span class="c1"># 清除所有環境&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl">hatch env prune&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="第四步版本管理hatch-version">第四步：版本管理（hatch version）&lt;/h3>
&lt;h4 id="設定版本來源">設定版本來源&lt;/h4>
&lt;h5 id="方法-a從檔案讀取版本">方法 A：從檔案讀取版本&lt;/h5>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">version&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="nx">path&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;src/my_awesome_lib/__about__.py&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># src/my_awesome_lib/__about__.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="n">__version__&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;0.1.0&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="方法-b從-git-標籤讀取版本推薦用於開源專案">方法 B：從 Git 標籤讀取版本（推薦用於開源專案）&lt;/h5>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">build-system&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="nx">requires&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;hatchling&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;hatch-vcs&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="nx">build-backend&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;hatchling.build&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">version&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="nx">source&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;vcs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hooks&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">vcs&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">9&lt;/span>&lt;span class="cl">&lt;span class="nx">version-file&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;src/my_awesome_lib/_version.py&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="版本操作">版本操作&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 顯示當前版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">hatch version
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 設定特定版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">hatch version 1.0.0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 語意化版本升級&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">hatch version patch &lt;span class="c1"># 0.1.0 → 0.1.1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">hatch version minor &lt;span class="c1"># 0.1.1 → 0.2.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">hatch version major &lt;span class="c1"># 0.2.0 → 1.0.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1"># 預發布版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">hatch version alpha &lt;span class="c1"># 1.0.0 → 1.0.1a0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">hatch version beta &lt;span class="c1"># 1.0.1a0 → 1.0.1b0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">hatch version rc &lt;span class="c1"># 1.0.1b0 → 1.0.1rc0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">hatch version release &lt;span class="c1"># 1.0.1rc0 → 1.0.1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="c1"># 開發版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">hatch version dev &lt;span class="c1"># 1.0.0 → 1.0.1.dev0&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="第五步建構與發布">第五步：建構與發布&lt;/h3>
&lt;h4 id="建構套件">建構套件&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 建構 wheel 和 sdist&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">hatch build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 只建構 wheel&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">hatch build --target wheel
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 只建構 sdist&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">hatch build --target sdist
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="c1"># 清除建構產物後重建&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">hatch build --clean&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="建構產物">建構產物&lt;/h5>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">dist/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">├── my_awesome_lib-0.1.0-py3-none-any.whl
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">└── my_awesome_lib-0.1.0.tar.gz&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="發布套件">發布套件&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 發布到 PyPI（需要設定認證）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">hatch publish
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 發布到 TestPyPI&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">hatch publish --repo &lt;span class="nb">test&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 指定發布的檔案&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">hatch publish dist/my_awesome_lib-0.1.0-py3-none-any.whl&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="設定-pypi-認證">設定 PyPI 認證&lt;/h5>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 設定 PyPI token&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">hatch config &lt;span class="nb">set&lt;/span> pypi.auth.username __token__
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">hatch config &lt;span class="nb">set&lt;/span> pypi.auth.password pypi-xxxxx
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="c1"># 或使用環境變數&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">HATCH_INDEX_USER&lt;/span>&lt;span class="o">=&lt;/span>__token__
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">HATCH_INDEX_AUTH&lt;/span>&lt;span class="o">=&lt;/span>pypi-xxxxx&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="pyprojecttoml-的-hatch-特定設定">pyproject.toml 的 Hatch 特定設定&lt;/h2>
&lt;h3 id="toolhatchbuild-建構設定">[tool.hatch.build] 建構設定&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c"># 包含的檔案（支援 glob）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">include&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;src/my_awesome_lib&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;README.md&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="c"># 排除的檔案&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="nx">exclude&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;*.pyc&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;__pycache__&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;.git&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="c"># 是否可重現建構&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="nx">reproducible&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="c"># 開發模式設定&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="nx">dev-mode-dirs&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;src&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">targets&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">sdist&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">&lt;span class="c"># 原始碼發布設定&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">&lt;span class="nx">include&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;/src&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;/tests&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;/README.md&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;/LICENSE.txt&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">targets&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">wheel&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl">&lt;span class="c"># Wheel 發布設定&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl">&lt;span class="nx">packages&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;src/my_awesome_lib&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">34&lt;/span>&lt;span class="cl">&lt;span class="c"># 只包含特定平台&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">35&lt;/span>&lt;span class="cl">&lt;span class="c"># only-include = [&amp;#34;my_awesome_lib&amp;#34;]&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="toolhatchenvs-環境設定">[tool.hatch.envs] 環境設定&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">default&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c"># 相依性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;pytest&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="c"># 額外安裝的 features&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="nx">features&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;yaml&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="c"># 環境變數&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">default&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">env-vars&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="nx">PYTHONPATH&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;src&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nx">LOG_LEVEL&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;DEBUG&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="c"># 腳本定義&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">default&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">scripts&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="nx">test&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;pytest {args}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="c"># 平台特定設定&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">default&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">overrides&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="nx">platform&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">windows&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">scripts&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl"> &lt;span class="s1">&amp;#39;test = &amp;#34;pytest --no-header {args}&amp;#34;&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="toolhatchversion-版本設定">[tool.hatch.version] 版本設定&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c"># 從檔案讀取&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">version&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">path&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;src/my_awesome_lib/__about__.py&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="nx">pattern&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^__version__ = [&amp;#39;\&amp;#34;](/python-advanced/07-packaging/case-studies/hatch-workflow/?P&amp;lt;version&amp;gt;[^&amp;#39;\&amp;#34;]+)[&amp;#39;\&amp;#34;]&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="c"># 從 VCS 讀取&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">version&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">source&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;vcs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="nx">raw-options&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">local_scheme&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;no-local-version&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hooks&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">vcs&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="nx">version-file&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;src/my_awesome_lib/_version.py&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="toolhatchmetadata-元資料設定">[tool.hatch.metadata] 元資料設定&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">metadata&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c"># 允許直接依賴（通常應該避免）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">allow-direct-references&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="c"># 動態讀取 README&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">metadata&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hooks&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">fancy-pypi-readme&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="nx">content-type&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;text/markdown&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="p">[[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">metadata&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hooks&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">fancy-pypi-readme&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">fragments&lt;/span>&lt;span class="p">]]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="nx">path&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;README.md&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="與-poetry-的比較">與 Poetry 的比較&lt;/h2>
&lt;h3 id="設計理念差異">設計理念差異&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">Hatch：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">├── 遵循 PEP 標準優先
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">├── 環境管理內建
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">├── 不提供依賴鎖定
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">├── 建構系統（hatchling）可獨立使用
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">└── 設定完全在 [tool.hatch]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">Poetry：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">├── 自有生態系統
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">├── 強調依賴鎖定（poetry.lock）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">├── 虛擬環境管理
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">├── poetry.core 可獨立使用
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">└── 混合 [project] 和 [tool.poetry]&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="功能對照">功能對照&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>功能&lt;/th>
 &lt;th>Hatch&lt;/th>
 &lt;th>Poetry&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>依賴鎖定&lt;/td>
 &lt;td>不支援&lt;/td>
 &lt;td>poetry.lock&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>環境管理&lt;/td>
 &lt;td>內建矩陣支援&lt;/td>
 &lt;td>單一環境&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>PEP 621&lt;/td>
 &lt;td>完全支援&lt;/td>
 &lt;td>Poetry 2.0 支援&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>腳本系統&lt;/td>
 &lt;td>強大（環境分離）&lt;/td>
 &lt;td>基本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>版本管理&lt;/td>
 &lt;td>內建 bump&lt;/td>
 &lt;td>需外掛或手動&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>插件系統&lt;/td>
 &lt;td>支援&lt;/td>
 &lt;td>支援&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="pyprojecttoml-比較">pyproject.toml 比較&lt;/h3>
&lt;h4 id="hatch-風格">Hatch 風格&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">build-system&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="nx">requires&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;hatchling&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">build-backend&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;hatchling.build&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my-package&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;1.0.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;requests&amp;gt;=2.28&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">optional-dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nx">dev&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;pytest&amp;gt;=8.0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">default&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="nx">features&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;dev&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="poetry-風格20">Poetry 風格（2.0）&lt;/h4>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">build-system&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="nx">requires&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;poetry-core&amp;gt;=2.0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">build-backend&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;poetry.core.masonry.api&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my-package&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="nx">version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;1.0.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;requests&amp;gt;=2.28&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">poetry&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dev&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nx">pytest&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;^8.0&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="選擇建議">選擇建議&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">選擇 Hatch：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">├── 開發 Python 函式庫
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">├── 需要多環境測試
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">├── 偏好標準優先
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">└── 不需要依賴鎖定
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">選擇 Poetry：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">├── 開發應用程式
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">├── 需要嚴格的依賴鎖定
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">├── 團隊習慣 Poetry 工作流
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">└── 需要與現有 Poetry 專案整合&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="實用技巧">實用技巧&lt;/h2>
&lt;h3 id="多環境測試矩陣">多環境測試矩陣&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c"># 定義多 Python 版本測試&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">test&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;pytest&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;pytest-cov&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="p">[[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">test&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">matrix&lt;/span>&lt;span class="p">]]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="nx">python&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;3.9&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;3.10&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;3.11&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;3.12&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;3.13&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">test&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">scripts&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="nx">run&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;pytest {args:tests}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="nx">cov&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;pytest --cov=my_awesome_lib {args:tests}&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 在所有矩陣環境執行測試&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">hatch run test:run
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 在特定版本執行&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">hatch run +py&lt;span class="o">=&lt;/span>3.12 test:run
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 顯示矩陣環境&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">hatch env show --ascii&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="複合腳本">複合腳本&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">default&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">scripts&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c"># 單一命令&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">test&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;pytest {args:tests}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="c"># 多命令（依序執行）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="nx">ci&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;ruff check src tests&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;pytest --cov&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;mypy src&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c"># 呼叫其他腳本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="nx">all&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;lint:check&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;test:cov&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="c"># 帶預設參數&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="nx">lint&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;ruff check {args:.}&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="環境繼承">環境繼承&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c"># 基礎環境&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">base&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;pytest&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="c"># 繼承基礎環境&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">coverage&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="nx">template&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;base&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;pytest-cov&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">coverage&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">scripts&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nx">run&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;pytest --cov {args:tests}&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="條件依賴">條件依賴&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">default&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;pytest&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="c"># 根據平台新增依賴&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">default&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">overrides&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">platform&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">linux&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;pytest-xdist&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="nx">platform&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">darwin&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;pytest-xdist&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="c"># 根據 Python 版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="nx">python&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mf">3.8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;typing-extensions&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="自訂建構-hook">自訂建構 Hook&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hooks&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">custom&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="c"># 建構前執行&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="nx">path&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;hatch_build.py&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># hatch_build.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">hatchling.builders.hooks.plugin.interface&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BuildHookInterface&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">CustomBuildHook&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BuildHookInterface&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">initialize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">version&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">build_data&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl"> &lt;span class="c1"># 建構前的自訂邏輯&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Building version &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">version&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="完整範例cli-應用程式">完整範例：CLI 應用程式&lt;/h2>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c"># pyproject.toml&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">build-system&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="nx">requires&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;hatchling&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="nx">build-backend&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;hatchling.build&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="nx">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my-cli&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">dynamic&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;version&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="nx">description&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;A useful CLI tool&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="nx">readme&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;README.md&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nx">requires-python&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;gt;=3.10&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="nx">license&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;MIT&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;click&amp;gt;=8.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;rich&amp;gt;=13.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">scripts&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl">&lt;span class="nx">my-cli&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;my_cli.main:app&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">project&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">optional-dependencies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">22&lt;/span>&lt;span class="cl">&lt;span class="nx">yaml&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;PyYAML&amp;gt;=6.0&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">23&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">24&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">version&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">25&lt;/span>&lt;span class="cl">&lt;span class="nx">path&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;src/my_cli/__about__.py&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">26&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">27&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">targets&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">wheel&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">28&lt;/span>&lt;span class="cl">&lt;span class="nx">packages&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;src/my_cli&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">29&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">30&lt;/span>&lt;span class="cl">&lt;span class="c"># ===== 環境設定 =====&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">31&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">32&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">default&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">33&lt;/span>&lt;span class="cl">&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">34&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;pytest&amp;gt;=8.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">35&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;pytest-cov&amp;gt;=4.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">36&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">37&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">38&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">default&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">scripts&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">39&lt;/span>&lt;span class="cl">&lt;span class="nx">test&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;pytest {args:tests}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">40&lt;/span>&lt;span class="cl">&lt;span class="nx">cov&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;pytest --cov=my_cli --cov-report=term-missing {args:tests}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">41&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">42&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">lint&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">43&lt;/span>&lt;span class="cl">&lt;span class="nx">dependencies&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">44&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;ruff&amp;gt;=0.4&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">45&lt;/span>&lt;span class="cl"> &lt;span class="s2">&amp;#34;mypy&amp;gt;=1.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">46&lt;/span>&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">47&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">48&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">lint&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">scripts&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">49&lt;/span>&lt;span class="cl">&lt;span class="nx">check&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;ruff check src tests&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;ruff format --check src tests&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">50&lt;/span>&lt;span class="cl">&lt;span class="nx">fix&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;ruff check --fix src tests&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;ruff format src tests&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">51&lt;/span>&lt;span class="cl">&lt;span class="nx">typing&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;mypy src&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">52&lt;/span>&lt;span class="cl">&lt;span class="nx">all&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;check&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;typing&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">53&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">54&lt;/span>&lt;span class="cl">&lt;span class="p">[[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">hatch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">envs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">test&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">matrix&lt;/span>&lt;span class="p">]]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">55&lt;/span>&lt;span class="cl">&lt;span class="nx">python&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;3.10&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;3.11&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;3.12&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;3.13&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">56&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">57&lt;/span>&lt;span class="cl">&lt;span class="c"># ===== 工具設定 =====&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">58&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">59&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ruff&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">60&lt;/span>&lt;span class="cl">&lt;span class="nx">src&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;src&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">61&lt;/span>&lt;span class="cl">&lt;span class="nx">line-length&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="mi">88&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">62&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">63&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ruff&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">lint&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">64&lt;/span>&lt;span class="cl">&lt;span class="nx">select&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;E&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;W&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;F&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;I&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;B&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;UP&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">65&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">66&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">mypy&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">67&lt;/span>&lt;span class="cl">&lt;span class="nx">python_version&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;3.10&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">68&lt;/span>&lt;span class="cl">&lt;span class="nx">strict&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">69&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">70&lt;/span>&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">tool&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">pytest&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ini_options&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">71&lt;/span>&lt;span class="cl">&lt;span class="nx">testpaths&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tests&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">72&lt;/span>&lt;span class="cl">&lt;span class="nx">addopts&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;-v&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="發布檢查清單">發布檢查清單&lt;/h2>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">發布前檢查：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">├── [ ] hatch run lint:all 通過
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">├── [ ] hatch run test:run 在所有 Python 版本通過
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">├── [ ] hatch version 更新版本號
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">├── [ ] 更新 CHANGELOG.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">├── [ ] hatch build 建構成功
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">├── [ ] 在虛擬環境測試安裝：pip install dist/*.whl
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">├── [ ] hatch publish --repo test 發布到 TestPyPI
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">├── [ ] 從 TestPyPI 測試安裝
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">└── [ ] hatch publish 發布到 PyPI&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="延伸閱讀">延伸閱讀&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://hatch.pypa.io/">Hatch 官方文件&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://hatch.pypa.io/latest/plugins/build-hook/reference/">Hatchling 建構後端&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://peps.python.org/pep-0621/">PEP 621 - pyproject.toml 元資料&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://packaging.python.org/">Python 打包使用者指南&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>返回：&lt;a href="https://tarrragon.github.io/blog/python-advanced/07-packaging/case-studies/" data-link-title="案例研究" data-link-desc="基於 .claude/lib 實際程式碼的打包發布案例">案例研究&lt;/a>&lt;/p></description><content:encoded><![CDATA[<p>本案例展示如何使用 Hatch 這個 PyPA 推薦的現代 Python 專案管理工具，完成從專案建立到發布的完整流程。</p>
<h2 id="先備知識">先備知識</h2>
<ul>
<li><a href="/blog/python-advanced/07-packaging/build-systems/" data-link-title="6.2 建構系統比較" data-link-desc="比較 setuptools、Poetry、Hatch 等建構系統">6.2 建構系統比較</a></li>
<li>Python 虛擬環境基礎</li>
<li>基本的命令列操作</li>
</ul>
<h2 id="問題背景">問題背景</h2>
<h3 id="hatch-是什麼">Hatch 是什麼？</h3>
<p>Hatch 是由 PyPA（Python Packaging Authority）成員開發維護的現代 Python 專案管理工具，整合了：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Hatch 功能整合：
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── 專案腳手架（hatch new）
</span></span><span class="line"><span class="ln">3</span><span class="cl">├── 環境管理（類似 tox + virtualenv）
</span></span><span class="line"><span class="ln">4</span><span class="cl">├── 版本管理（自動更新版本號）
</span></span><span class="line"><span class="ln">5</span><span class="cl">├── 建構系統（hatchling）
</span></span><span class="line"><span class="ln">6</span><span class="cl">└── 發布工具（hatch publish）</span></span></code></pre></div><h3 id="為什麼選擇-hatch">為什麼選擇 Hatch？</h3>
<table>
  <thead>
      <tr>
          <th>優勢</th>
          <th>說明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>標準優先</strong></td>
          <td>完全遵循 PEP 517/518/621 標準</td>
      </tr>
      <tr>
          <td><strong>一站式工具</strong></td>
          <td>不需要額外安裝 tox、virtualenv、bump2version</td>
      </tr>
      <tr>
          <td><strong>快速建構</strong></td>
          <td>hatchling 建構速度優於 setuptools</td>
      </tr>
      <tr>
          <td><strong>環境矩陣</strong></td>
          <td>內建多 Python 版本測試支援</td>
      </tr>
      <tr>
          <td><strong>腳本系統</strong></td>
          <td>定義可重用的專案腳本</td>
      </tr>
  </tbody>
</table>
<h2 id="完整工作流">完整工作流</h2>
<h3 id="第一步安裝-hatch">第一步：安裝 Hatch</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 使用 pip 安裝</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">pip install hatch
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># 或使用 pipx（推薦，隔離安裝）</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">pipx install hatch
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"># 驗證安裝</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">hatch --version</span></span></code></pre></div><h3 id="第二步建立新專案">第二步：建立新專案</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 建立新專案</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">hatch new my-awesome-lib
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># 互動式建立（可自訂選項）</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">hatch new my-awesome-lib --init
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"># 建立應用程式專案（非函式庫）</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">hatch new --cli my-cli-app</span></span></code></pre></div><h4 id="預設專案結構">預設專案結構</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">my-awesome-lib/
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── src/
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">│   └── my_awesome_lib/
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">│       ├── __init__.py
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">│       └── __about__.py      # 版本資訊
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">├── tests/
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">│   └── __init__.py
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">├── pyproject.toml
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">├── README.md
</span></span><span class="line"><span class="ln">10</span><span class="cl">└── LICENSE.txt</span></span></code></pre></div><h4 id="生成的-pyprojecttoml">生成的 pyproject.toml</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">build-system</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nx">requires</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;hatchling&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">build-backend</span> <span class="p">=</span> <span class="s2">&#34;hatchling.build&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;my-awesome-lib&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">dynamic</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;version&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">description</span> <span class="p">=</span> <span class="s1">&#39;&#39;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nx">readme</span> <span class="p">=</span> <span class="s2">&#34;README.md&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nx">requires-python</span> <span class="p">=</span> <span class="s2">&#34;&gt;=3.8&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">license</span> <span class="p">=</span> <span class="s2">&#34;MIT&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nx">keywords</span> <span class="p">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nx">authors</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">  <span class="p">{</span> <span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;Your Name&#34;</span><span class="p">,</span> <span class="nx">email</span> <span class="p">=</span> <span class="s2">&#34;you@example.com&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="nx">classifiers</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">  <span class="s2">&#34;Development Status :: 4 - Beta&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">  <span class="s2">&#34;Programming Language :: Python&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">  <span class="s2">&#34;Programming Language :: Python :: 3.8&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">  <span class="s2">&#34;Programming Language :: Python :: 3.9&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">  <span class="s2">&#34;Programming Language :: Python :: 3.10&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">  <span class="s2">&#34;Programming Language :: Python :: 3.11&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">  <span class="s2">&#34;Programming Language :: Python :: 3.12&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">urls</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="nx">Documentation</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/yourname/my-awesome-lib#readme&#34;</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="nx">Issues</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/yourname/my-awesome-lib/issues&#34;</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="nx">Source</span> <span class="p">=</span> <span class="s2">&#34;https://github.com/yourname/my-awesome-lib&#34;</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">version</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="nx">path</span> <span class="p">=</span> <span class="s2">&#34;src/my_awesome_lib/__about__.py&#34;</span></span></span></code></pre></div><h3 id="第三步環境管理hatch-env">第三步：環境管理（hatch env）</h3>
<h4 id="定義環境">定義環境</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c"># pyproject.toml</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="c"># 預設環境</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">default</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">  <span class="s2">&#34;pytest&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  <span class="s2">&#34;pytest-cov&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">default</span><span class="p">.</span><span class="nx">scripts</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">test</span> <span class="p">=</span> <span class="s2">&#34;pytest {args:tests}&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nx">test-cov</span> <span class="p">=</span> <span class="s2">&#34;pytest --cov=my_awesome_lib --cov-report=term-missing {args:tests}&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c"># Lint 環境</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">lint</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">  <span class="s2">&#34;ruff&gt;=0.4&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">  <span class="s2">&#34;mypy&gt;=1.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">lint</span><span class="p">.</span><span class="nx">scripts</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="nx">check</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">  <span class="s2">&#34;ruff check src tests&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">  <span class="s2">&#34;ruff format --check src tests&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="nx">fix</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">  <span class="s2">&#34;ruff check --fix src tests&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">  <span class="s2">&#34;ruff format src tests&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="nx">typing</span> <span class="p">=</span> <span class="s2">&#34;mypy src&#34;</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="nx">all</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;check&#34;</span><span class="p">,</span> <span class="s2">&#34;typing&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="c"># 文件環境</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">docs</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">  <span class="s2">&#34;mkdocs&gt;=1.5&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">  <span class="s2">&#34;mkdocs-material&gt;=9.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl">
</span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">docs</span><span class="p">.</span><span class="nx">scripts</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="nx">build</span> <span class="p">=</span> <span class="s2">&#34;mkdocs build&#34;</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="nx">serve</span> <span class="p">=</span> <span class="s2">&#34;mkdocs serve&#34;</span></span></span></code></pre></div><h4 id="使用環境">使用環境</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 顯示所有環境</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">hatch env show
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 執行預設環境的腳本</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">hatch run <span class="nb">test</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">hatch run test-cov
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"># 執行特定環境的腳本</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">hatch run lint:check
</span></span><span class="line"><span class="ln">10</span><span class="cl">hatch run lint:fix
</span></span><span class="line"><span class="ln">11</span><span class="cl">hatch run lint:typing
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1"># 進入環境 shell</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">hatch shell
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="c1"># 進入特定環境</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">hatch shell lint
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="c1"># 移除環境</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">hatch env remove
</span></span><span class="line"><span class="ln">21</span><span class="cl">hatch env remove lint
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="c1"># 清除所有環境</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">hatch env prune</span></span></code></pre></div><h3 id="第四步版本管理hatch-version">第四步：版本管理（hatch version）</h3>
<h4 id="設定版本來源">設定版本來源</h4>
<h5 id="方法-a從檔案讀取版本">方法 A：從檔案讀取版本</h5>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">version</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nx">path</span> <span class="p">=</span> <span class="s2">&#34;src/my_awesome_lib/__about__.py&#34;</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># src/my_awesome_lib/__about__.py</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">__version__</span> <span class="o">=</span> <span class="s2">&#34;0.1.0&#34;</span></span></span></code></pre></div><h5 id="方法-b從-git-標籤讀取版本推薦用於開源專案">方法 B：從 Git 標籤讀取版本（推薦用於開源專案）</h5>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">[</span><span class="nx">build-system</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nx">requires</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;hatchling&#34;</span><span class="p">,</span> <span class="s2">&#34;hatch-vcs&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nx">build-backend</span> <span class="p">=</span> <span class="s2">&#34;hatchling.build&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">version</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nx">source</span> <span class="p">=</span> <span class="s2">&#34;vcs&#34;</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">build</span><span class="p">.</span><span class="nx">hooks</span><span class="p">.</span><span class="nx">vcs</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="nx">version-file</span> <span class="p">=</span> <span class="s2">&#34;src/my_awesome_lib/_version.py&#34;</span></span></span></code></pre></div><h4 id="版本操作">版本操作</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 顯示當前版本</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">hatch version
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 設定特定版本</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">hatch version 1.0.0
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># 語意化版本升級</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">hatch version patch   <span class="c1"># 0.1.0 → 0.1.1</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">hatch version minor   <span class="c1"># 0.1.1 → 0.2.0</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">hatch version major   <span class="c1"># 0.2.0 → 1.0.0</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"># 預發布版本</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">hatch version alpha   <span class="c1"># 1.0.0 → 1.0.1a0</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">hatch version beta    <span class="c1"># 1.0.1a0 → 1.0.1b0</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">hatch version rc      <span class="c1"># 1.0.1b0 → 1.0.1rc0</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">hatch version release <span class="c1"># 1.0.1rc0 → 1.0.1</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"># 開發版本</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">hatch version dev     <span class="c1"># 1.0.0 → 1.0.1.dev0</span></span></span></code></pre></div><h3 id="第五步建構與發布">第五步：建構與發布</h3>
<h4 id="建構套件">建構套件</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 建構 wheel 和 sdist</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">hatch build
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 只建構 wheel</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">hatch build --target wheel
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># 只建構 sdist</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">hatch build --target sdist
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># 清除建構產物後重建</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">hatch build --clean</span></span></code></pre></div><h5 id="建構產物">建構產物</h5>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">dist/
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── my_awesome_lib-0.1.0-py3-none-any.whl
</span></span><span class="line"><span class="ln">3</span><span class="cl">└── my_awesome_lib-0.1.0.tar.gz</span></span></code></pre></div><h4 id="發布套件">發布套件</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 發布到 PyPI（需要設定認證）</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">hatch publish
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># 發布到 TestPyPI</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">hatch publish --repo <span class="nb">test</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"># 指定發布的檔案</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">hatch publish dist/my_awesome_lib-0.1.0-py3-none-any.whl</span></span></code></pre></div><h5 id="設定-pypi-認證">設定 PyPI 認證</h5>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 設定 PyPI token</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">hatch config <span class="nb">set</span> pypi.auth.username __token__
</span></span><span class="line"><span class="ln">3</span><span class="cl">hatch config <span class="nb">set</span> pypi.auth.password pypi-xxxxx
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"># 或使用環境變數</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nb">export</span> <span class="nv">HATCH_INDEX_USER</span><span class="o">=</span>__token__
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="nb">export</span> <span class="nv">HATCH_INDEX_AUTH</span><span class="o">=</span>pypi-xxxxx</span></span></code></pre></div><h2 id="pyprojecttoml-的-hatch-特定設定">pyproject.toml 的 Hatch 特定設定</h2>
<h3 id="toolhatchbuild-建構設定">[tool.hatch.build] 建構設定</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">build</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c"># 包含的檔案（支援 glob）</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">include</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  <span class="s2">&#34;src/my_awesome_lib&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">  <span class="s2">&#34;README.md&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c"># 排除的檔案</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nx">exclude</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">  <span class="s2">&#34;*.pyc&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">  <span class="s2">&#34;__pycache__&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  <span class="s2">&#34;.git&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c"># 是否可重現建構</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="nx">reproducible</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c"># 開發模式設定</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="nx">dev-mode-dirs</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;src&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">build</span><span class="p">.</span><span class="nx">targets</span><span class="p">.</span><span class="nx">sdist</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="c"># 原始碼發布設定</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="nx">include</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">  <span class="s2">&#34;/src&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">  <span class="s2">&#34;/tests&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">  <span class="s2">&#34;/README.md&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">  <span class="s2">&#34;/LICENSE.txt&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">build</span><span class="p">.</span><span class="nx">targets</span><span class="p">.</span><span class="nx">wheel</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="c"># Wheel 發布設定</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="nx">packages</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;src/my_awesome_lib&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">
</span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="c"># 只包含特定平台</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="c"># only-include = [&#34;my_awesome_lib&#34;]</span></span></span></code></pre></div><h3 id="toolhatchenvs-環境設定">[tool.hatch.envs] 環境設定</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">default</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c"># 相依性</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;pytest&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c"># 額外安裝的 features</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nx">features</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;yaml&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c"># 環境變數</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">default</span><span class="p">.</span><span class="nx">env-vars</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nx">PYTHONPATH</span> <span class="p">=</span> <span class="s2">&#34;src&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">LOG_LEVEL</span> <span class="p">=</span> <span class="s2">&#34;DEBUG&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c"># 腳本定義</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">default</span><span class="p">.</span><span class="nx">scripts</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="nx">test</span> <span class="p">=</span> <span class="s2">&#34;pytest {args}&#34;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="c"># 平台特定設定</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">default</span><span class="p">.</span><span class="nx">overrides</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="nx">platform</span><span class="p">.</span><span class="nx">windows</span><span class="p">.</span><span class="nx">scripts</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">  <span class="s1">&#39;test = &#34;pytest --no-header {args}&#34;&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="p">]</span></span></span></code></pre></div><h3 id="toolhatchversion-版本設定">[tool.hatch.version] 版本設定</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c"># 從檔案讀取</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">version</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">path</span> <span class="p">=</span> <span class="s2">&#34;src/my_awesome_lib/__about__.py&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nx">pattern</span> <span class="p">=</span> <span class="s2">&#34;^__version__ = [&#39;\&#34;](/python-advanced/07-packaging/case-studies/hatch-workflow/?P&lt;version&gt;[^&#39;\&#34;]+)[&#39;\&#34;]&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c"># 從 VCS 讀取</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">version</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">source</span> <span class="p">=</span> <span class="s2">&#34;vcs&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nx">raw-options</span> <span class="p">=</span> <span class="p">{</span> <span class="nx">local_scheme</span> <span class="p">=</span> <span class="s2">&#34;no-local-version&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">build</span><span class="p">.</span><span class="nx">hooks</span><span class="p">.</span><span class="nx">vcs</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nx">version-file</span> <span class="p">=</span> <span class="s2">&#34;src/my_awesome_lib/_version.py&#34;</span></span></span></code></pre></div><h3 id="toolhatchmetadata-元資料設定">[tool.hatch.metadata] 元資料設定</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">metadata</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c"># 允許直接依賴（通常應該避免）</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">allow-direct-references</span> <span class="p">=</span> <span class="kc">false</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c"># 動態讀取 README</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">metadata</span><span class="p">.</span><span class="nx">hooks</span><span class="p">.</span><span class="nx">fancy-pypi-readme</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">content-type</span> <span class="p">=</span> <span class="s2">&#34;text/markdown&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">[[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">metadata</span><span class="p">.</span><span class="nx">hooks</span><span class="p">.</span><span class="nx">fancy-pypi-readme</span><span class="p">.</span><span class="nx">fragments</span><span class="p">]]</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nx">path</span> <span class="p">=</span> <span class="s2">&#34;README.md&#34;</span></span></span></code></pre></div><h2 id="與-poetry-的比較">與 Poetry 的比較</h2>
<h3 id="設計理念差異">設計理念差異</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">Hatch：
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── 遵循 PEP 標準優先
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">├── 環境管理內建
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">├── 不提供依賴鎖定
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">├── 建構系統（hatchling）可獨立使用
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">└── 設定完全在 [tool.hatch]
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">Poetry：
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">├── 自有生態系統
</span></span><span class="line"><span class="ln">10</span><span class="cl">├── 強調依賴鎖定（poetry.lock）
</span></span><span class="line"><span class="ln">11</span><span class="cl">├── 虛擬環境管理
</span></span><span class="line"><span class="ln">12</span><span class="cl">├── poetry.core 可獨立使用
</span></span><span class="line"><span class="ln">13</span><span class="cl">└── 混合 [project] 和 [tool.poetry]</span></span></code></pre></div><h3 id="功能對照">功能對照</h3>
<table>
  <thead>
      <tr>
          <th>功能</th>
          <th>Hatch</th>
          <th>Poetry</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>依賴鎖定</td>
          <td>不支援</td>
          <td>poetry.lock</td>
      </tr>
      <tr>
          <td>環境管理</td>
          <td>內建矩陣支援</td>
          <td>單一環境</td>
      </tr>
      <tr>
          <td>PEP 621</td>
          <td>完全支援</td>
          <td>Poetry 2.0 支援</td>
      </tr>
      <tr>
          <td>腳本系統</td>
          <td>強大（環境分離）</td>
          <td>基本</td>
      </tr>
      <tr>
          <td>版本管理</td>
          <td>內建 bump</td>
          <td>需外掛或手動</td>
      </tr>
      <tr>
          <td>插件系統</td>
          <td>支援</td>
          <td>支援</td>
      </tr>
  </tbody>
</table>
<h3 id="pyprojecttoml-比較">pyproject.toml 比較</h3>
<h4 id="hatch-風格">Hatch 風格</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">build-system</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nx">requires</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;hatchling&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">build-backend</span> <span class="p">=</span> <span class="s2">&#34;hatchling.build&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;my-package&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;1.0.0&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;requests&gt;=2.28&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">optional-dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">dev</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;pytest&gt;=8.0&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">default</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="nx">features</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;dev&#34;</span><span class="p">]</span></span></span></code></pre></div><h4 id="poetry-風格20">Poetry 風格（2.0）</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">build-system</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nx">requires</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;poetry-core&gt;=2.0&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">build-backend</span> <span class="p">=</span> <span class="s2">&#34;poetry.core.masonry.api&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;my-package&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">version</span> <span class="p">=</span> <span class="s2">&#34;1.0.0&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;requests&gt;=2.28&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">poetry</span><span class="p">.</span><span class="nx">group</span><span class="p">.</span><span class="nx">dev</span><span class="p">.</span><span class="nx">dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">pytest</span> <span class="p">=</span> <span class="s2">&#34;^8.0&#34;</span></span></span></code></pre></div><h3 id="選擇建議">選擇建議</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">選擇 Hatch：
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── 開發 Python 函式庫
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">├── 需要多環境測試
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">├── 偏好標準優先
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">└── 不需要依賴鎖定
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">選擇 Poetry：
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">├── 開發應用程式
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">├── 需要嚴格的依賴鎖定
</span></span><span class="line"><span class="ln">10</span><span class="cl">├── 團隊習慣 Poetry 工作流
</span></span><span class="line"><span class="ln">11</span><span class="cl">└── 需要與現有 Poetry 專案整合</span></span></code></pre></div><h2 id="實用技巧">實用技巧</h2>
<h3 id="多環境測試矩陣">多環境測試矩陣</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c"># 定義多 Python 版本測試</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">test</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;pytest&#34;</span><span class="p">,</span> <span class="s2">&#34;pytest-cov&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">[[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">test</span><span class="p">.</span><span class="nx">matrix</span><span class="p">]]</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nx">python</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;3.9&#34;</span><span class="p">,</span> <span class="s2">&#34;3.10&#34;</span><span class="p">,</span> <span class="s2">&#34;3.11&#34;</span><span class="p">,</span> <span class="s2">&#34;3.12&#34;</span><span class="p">,</span> <span class="s2">&#34;3.13&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">test</span><span class="p">.</span><span class="nx">scripts</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nx">run</span> <span class="p">=</span> <span class="s2">&#34;pytest {args:tests}&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nx">cov</span> <span class="p">=</span> <span class="s2">&#34;pytest --cov=my_awesome_lib {args:tests}&#34;</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 在所有矩陣環境執行測試</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">hatch run test:run
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># 在特定版本執行</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">hatch run +py<span class="o">=</span>3.12 test:run
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"># 顯示矩陣環境</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">hatch env show --ascii</span></span></code></pre></div><h3 id="複合腳本">複合腳本</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">default</span><span class="p">.</span><span class="nx">scripts</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c"># 單一命令</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">test</span> <span class="p">=</span> <span class="s2">&#34;pytest {args:tests}&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c"># 多命令（依序執行）</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nx">ci</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  <span class="s2">&#34;ruff check src tests&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">  <span class="s2">&#34;pytest --cov&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">  <span class="s2">&#34;mypy src&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c"># 呼叫其他腳本</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nx">all</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;lint:check&#34;</span><span class="p">,</span> <span class="s2">&#34;test:cov&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c"># 帶預設參數</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="nx">lint</span> <span class="p">=</span> <span class="s2">&#34;ruff check {args:.}&#34;</span></span></span></code></pre></div><h3 id="環境繼承">環境繼承</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c"># 基礎環境</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">base</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;pytest&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c"># 繼承基礎環境</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">coverage</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">template</span> <span class="p">=</span> <span class="s2">&#34;base&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;pytest-cov&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">coverage</span><span class="p">.</span><span class="nx">scripts</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">run</span> <span class="p">=</span> <span class="s2">&#34;pytest --cov {args:tests}&#34;</span></span></span></code></pre></div><h3 id="條件依賴">條件依賴</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">default</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  <span class="s2">&#34;pytest&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c"># 根據平台新增依賴</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">default</span><span class="p">.</span><span class="nx">overrides</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">platform</span><span class="p">.</span><span class="nx">linux</span><span class="p">.</span><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;pytest-xdist&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nx">platform</span><span class="p">.</span><span class="nx">darwin</span><span class="p">.</span><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;pytest-xdist&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c"># 根據 Python 版本</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nx">python</span><span class="p">.</span><span class="mf">3.8</span><span class="p">.</span><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;typing-extensions&#34;</span><span class="p">]</span></span></span></code></pre></div><h3 id="自訂建構-hook">自訂建構 Hook</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">build</span><span class="p">.</span><span class="nx">hooks</span><span class="p">.</span><span class="nx">custom</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c"># 建構前執行</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nx">path</span> <span class="p">=</span> <span class="s2">&#34;hatch_build.py&#34;</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># hatch_build.py</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kn">from</span> <span class="nn">hatchling.builders.hooks.plugin.interface</span> <span class="kn">import</span> <span class="n">BuildHookInterface</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">class</span> <span class="nc">CustomBuildHook</span><span class="p">(</span><span class="n">BuildHookInterface</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">version</span><span class="p">,</span> <span class="n">build_data</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">        <span class="c1"># 建構前的自訂邏輯</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Building version </span><span class="si">{</span><span class="n">version</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span></span></span></code></pre></div><h2 id="完整範例cli-應用程式">完整範例：CLI 應用程式</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c"># pyproject.toml</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="p">[</span><span class="nx">build-system</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="nx">requires</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;hatchling&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nx">build-backend</span> <span class="p">=</span> <span class="s2">&#34;hatchling.build&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;my-cli&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nx">dynamic</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;version&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nx">description</span> <span class="p">=</span> <span class="s2">&#34;A useful CLI tool&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nx">readme</span> <span class="p">=</span> <span class="s2">&#34;README.md&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">requires-python</span> <span class="p">=</span> <span class="s2">&#34;&gt;=3.10&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nx">license</span> <span class="p">=</span> <span class="s2">&#34;MIT&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">  <span class="s2">&#34;click&gt;=8.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">  <span class="s2">&#34;rich&gt;=13.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">scripts</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="nx">my-cli</span> <span class="p">=</span> <span class="s2">&#34;my_cli.main:app&#34;</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="p">[</span><span class="nx">project</span><span class="p">.</span><span class="nx">optional-dependencies</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="nx">yaml</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;PyYAML&gt;=6.0&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">
</span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">version</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="nx">path</span> <span class="p">=</span> <span class="s2">&#34;src/my_cli/__about__.py&#34;</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">build</span><span class="p">.</span><span class="nx">targets</span><span class="p">.</span><span class="nx">wheel</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="nx">packages</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;src/my_cli&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="c"># ===== 環境設定 =====</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">default</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">  <span class="s2">&#34;pytest&gt;=8.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">  <span class="s2">&#34;pytest-cov&gt;=4.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">
</span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">default</span><span class="p">.</span><span class="nx">scripts</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="nx">test</span> <span class="p">=</span> <span class="s2">&#34;pytest {args:tests}&#34;</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="nx">cov</span> <span class="p">=</span> <span class="s2">&#34;pytest --cov=my_cli --cov-report=term-missing {args:tests}&#34;</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">
</span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">lint</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="nx">dependencies</span> <span class="p">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln">44</span><span class="cl">  <span class="s2">&#34;ruff&gt;=0.4&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">45</span><span class="cl">  <span class="s2">&#34;mypy&gt;=1.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln">47</span><span class="cl">
</span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">lint</span><span class="p">.</span><span class="nx">scripts</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="nx">check</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;ruff check src tests&#34;</span><span class="p">,</span> <span class="s2">&#34;ruff format --check src tests&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="nx">fix</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;ruff check --fix src tests&#34;</span><span class="p">,</span> <span class="s2">&#34;ruff format src tests&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">51</span><span class="cl"><span class="nx">typing</span> <span class="p">=</span> <span class="s2">&#34;mypy src&#34;</span>
</span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="nx">all</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;check&#34;</span><span class="p">,</span> <span class="s2">&#34;typing&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">53</span><span class="cl">
</span></span><span class="line"><span class="ln">54</span><span class="cl"><span class="p">[[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">hatch</span><span class="p">.</span><span class="nx">envs</span><span class="p">.</span><span class="nx">test</span><span class="p">.</span><span class="nx">matrix</span><span class="p">]]</span>
</span></span><span class="line"><span class="ln">55</span><span class="cl"><span class="nx">python</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;3.10&#34;</span><span class="p">,</span> <span class="s2">&#34;3.11&#34;</span><span class="p">,</span> <span class="s2">&#34;3.12&#34;</span><span class="p">,</span> <span class="s2">&#34;3.13&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">56</span><span class="cl">
</span></span><span class="line"><span class="ln">57</span><span class="cl"><span class="c"># ===== 工具設定 =====</span>
</span></span><span class="line"><span class="ln">58</span><span class="cl">
</span></span><span class="line"><span class="ln">59</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">ruff</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">60</span><span class="cl"><span class="nx">src</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;src&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">61</span><span class="cl"><span class="nx">line-length</span> <span class="p">=</span> <span class="mi">88</span>
</span></span><span class="line"><span class="ln">62</span><span class="cl">
</span></span><span class="line"><span class="ln">63</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">ruff</span><span class="p">.</span><span class="nx">lint</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">64</span><span class="cl"><span class="nx">select</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;E&#34;</span><span class="p">,</span> <span class="s2">&#34;W&#34;</span><span class="p">,</span> <span class="s2">&#34;F&#34;</span><span class="p">,</span> <span class="s2">&#34;I&#34;</span><span class="p">,</span> <span class="s2">&#34;B&#34;</span><span class="p">,</span> <span class="s2">&#34;UP&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">65</span><span class="cl">
</span></span><span class="line"><span class="ln">66</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">mypy</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">67</span><span class="cl"><span class="nx">python_version</span> <span class="p">=</span> <span class="s2">&#34;3.10&#34;</span>
</span></span><span class="line"><span class="ln">68</span><span class="cl"><span class="nx">strict</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="ln">69</span><span class="cl">
</span></span><span class="line"><span class="ln">70</span><span class="cl"><span class="p">[</span><span class="nx">tool</span><span class="p">.</span><span class="nx">pytest</span><span class="p">.</span><span class="nx">ini_options</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">71</span><span class="cl"><span class="nx">testpaths</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;tests&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">72</span><span class="cl"><span class="nx">addopts</span> <span class="p">=</span> <span class="s2">&#34;-v&#34;</span></span></span></code></pre></div><h2 id="發布檢查清單">發布檢查清單</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">發布前檢查：
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">├── [ ] hatch run lint:all 通過
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">├── [ ] hatch run test:run 在所有 Python 版本通過
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">├── [ ] hatch version 更新版本號
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">├── [ ] 更新 CHANGELOG.md
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">├── [ ] hatch build 建構成功
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">├── [ ] 在虛擬環境測試安裝：pip install dist/*.whl
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">├── [ ] hatch publish --repo test 發布到 TestPyPI
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">├── [ ] 從 TestPyPI 測試安裝
</span></span><span class="line"><span class="ln">10</span><span class="cl">└── [ ] hatch publish 發布到 PyPI</span></span></code></pre></div><h2 id="延伸閱讀">延伸閱讀</h2>
<ul>
<li><a href="https://hatch.pypa.io/">Hatch 官方文件</a></li>
<li><a href="https://hatch.pypa.io/latest/plugins/build-hook/reference/">Hatchling 建構後端</a></li>
<li><a href="https://peps.python.org/pep-0621/">PEP 621 - pyproject.toml 元資料</a></li>
<li><a href="https://packaging.python.org/">Python 打包使用者指南</a></li>
</ul>
<hr>
<p>返回：<a href="/blog/python-advanced/07-packaging/case-studies/" data-link-title="案例研究" data-link-desc="基於 .claude/lib 實際程式碼的打包發布案例">案例研究</a></p>
]]></content:encoded></item></channel></rss>