程式寫久了都會遇到在多個專案中重複寫一樣的東西,例如工具類程式、常用的介面程式、基礎算法程式等等,重複的東西就會違背 DRY (Don’t Repeat Yourself) 原則,今天這篇文就來示範一下如何自己建立自己的 Python 包,然後上傳到公有或私有 server,最後能透過 pip install
來安裝已打包好的程式,文章會分為 2 個部份,第 1 部份是如何打包,第 2 部份是把我們打包好的程式上傳到公開的庫 PyPI (Python package index) 或者私有的庫 pypiserver。
打包你的 Python 程式
首先我們要有想打包的程式,資料夾結構會長的跟下面一樣,
└── tshine73-utils <--- 這個是 "project name",也就是之後會用 pip install 時用的名字
└── tshine73_utils <--- 這個是 "package name",也就是未來在程式中 import 時用的名字
├── __init__.py
└── aws
└── code1.py
└── __init__.py
├── code1.py
└── code2.py
├── README.md
├── requirements.txt
└── setup.py
這裡可以留意一下 project name 和 package name 的差別,準備好程式後,就可以照著以下的步驟進行打包啦!
若懶得整理你自己程式可用 我的程式 來練習打包。
1. 安裝 twine
因為我們是用 twine 來上傳 Python 包,所以要裝。
pip install twine==6.1.0
2. 準備好 setup.py
這個檔案是用來定義 Python 包的 metadata,要留意一下 install_requires
這個參數,需要把你的程式中有用到的 Python 依賴包都放入。
from setuptools import setup, find_packages
setup(
name="tshine73-utils",
version="0.2",
author="tshine73",
author_email="fan.steven.chiang@gmail.com",
description="tshine73 utils",
packages=find_packages(),
classifiers=[
'Programming Language :: Python :: 3',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
],
python_requires='>=3.12',
include_package_data=True,
install_requires=[
"psycopg2-binary==2.9.9", 'boto3==1.36.3', 'requests==2.32.3'
]
)
3. 打包
執行下述指令,
python setup.py sdist
然後你會看到多了 2 個資料夾 dist
和 xxxx-info
,如下圖紅字。

4. 使用 pip 安裝一下剛剛打包的 Python 包,然後寫個程式測試一下
用 .
來安裝 dist 資料夾中的 Python 包,
pip install .
然後隨便寫個程式測試一下是不是真的可以在 import 你的 Python 包進來,
from datetime import datetime
from tshine73_utils.date_utils import format_datetime
def main():
current_date_time = format_datetime(datetime.now())
print(f"current date time is {current_date_time}")
if __name__ == "__main__":
main()
看起來可以成功執行,

最後可以解除安裝,一會 上傳我們的 Python 包後可以再測試安裝一次。
pip uninstall tshine73-utils
上傳你的 Python 包到公有或私有環境
上傳 Python 包到公有環境 PyPI
PyPI 是 Python 的包索引,你在執行 pip install
時預設都會來這裡找相依的包,所以我們也可以把我們的包上傳到這裡,讓社群的大家都可以使用😃
1. 註冊 PyPI 會員
上傳前你需要先去註冊 PyPI 會員,完成 2 階段認證設定後,在 Account setting 中新增 API token,


2. 使用 twine 上傳 Python 包
使用以下指令後上傳,
twine upload dist/*
然後它會要你輸入上一步取得的 API Token,完成後會看到下圖。

3. 安裝測試
這次我們就來輸入 project name tshine73-utils
來測試一下安裝。
pip install tshine73-utils
成功安裝!

上傳 Python 包到私有環境 PyPI
PyPI 的 私有server 有很多,這裡就選擇一個較熱門的 pypiserver,它跟 PyPI 都實作一樣的介面,所以我們也可以用相同的 pip 和 twine 指令行安裝和上傳,它的方便也在於用 pip install pypiserver
後,就可以直接用它的指令啟動 server 起來了,為求環境獨立性,我這裡使用 docker 來啟動 pypiserver。
1. 使用 docker run 啟動 pypiserver
感謝網路上已經有相對應的 pypiserver docker image 可使用,使用以下指令啟動 pypiserver 可讓我們不透過認證就可以上傳 Python 包到 server 上。
docker run --rm -it --name pypiserver -p 8080:8080 -v ./packages:/data/packages pypiserver/pypiserver run -a . -P . -p 8080 --server gunicorn
啟動後,可透過 http://localhost:8080 連線看看,成功後會看到下圖。

2. 使用 twine 上傳 Python 包
因為是將 Python 包上傳到自己建立的 server,所以我們在用 twine 指令時需多指定 repository URL,
twine upload dist/* --repository-url http://localhost:8080
然後畫面會跳出要你輸入 username 和 password 的提示,直接按 enter 就好。

3. 安裝測試
使用一樣的 pip 指令,但這次我們要給它自建 server 的 URL,
pip install tshine73-utils --index-url http://localhost:8080
感謝老天也是成功安裝。

結論
今天的文章介紹了如何打包自己的 Python 程式然後上傳到公有或私有 server 上,這樣就不會老是在多個專案中將程式複製來複製去的吧!
最重要的是我們遵守了 DRY (Don’t Repeat Yourself) 開發原則,很棒對吧😎