打包python套件上傳PyPI
依賴套件管理
專案中的python package我是用poetry管理
好處是可以分開開發時才使用的套件跟程式執行時依賴的套件
移除不用的套件時還可以確認依賴套件的依賴套件也全部被移除了
這點是pip做不到的,他只會移除你指定的套件
這文章寫的很詳細如何使用poetry
雖然其他如virtualenv和pyvenv也可以建立python虛擬環境
但也是無法完全地管理依賴套件版本
專案結構
以我這次寫的專案Juno
為例,這個專案目錄下的結構如下
juno這個目錄就是python packages
pyproject.toml是poetry init
生成
每次用poetry add [pkg_name]
就會自動寫入pyproject.toml
當然移除的話也會從pyproject.toml移除
setup.py是在根目錄的第1層
可以使用poetry2setup先生成setup.py之後在依照自己需求微調
撰寫 setup.py
以前寫的專案都是自己寫腳本去自動安裝依賴的套件
因為寫setup.py
太麻煩了
不過現在也有很多套件可以輔助生成setup.py
像poetry2setup
這個套件可以直接從pyproject.toml輸出setup.py
之前就在好奇為何像eggnog-mapper
可以用pip install
然後在/anaconda3/bin/emapper.py
的位置會出現這個腳本
套件不是都安裝在/anaconda3/lib/python3/site-packages/
之類的地方
原來是用setup.py可以設定
像eggnog-mapper是直接寫腳本然後直接寫在setup.cfg
比較常見的會是直接寫在套件裡面的某個module中的function
像是porchop作者就是這樣處理
setup.py中的entry_points={"console_scripts": ['porechop = porechop.porechop:main']}
表示將porechop套件中porchop模組的main函式指定為腳本並且執行檔名稱為porechop
但他還是很貼心的直接在專案目錄寫一個porechop-runner.py
腳本
這腳本內容等同於執行python setup.py install
之後生成的porechop
|
|
客製化安裝步驟
雖然python的依賴套件直接在install_requires
指定就好,但如果使用非python的套件就需要特別寫安裝的函式
可以發現Flye的作者就有這樣處理安裝minimap2的過程
他的setup.py內容不是真的很長可以直接看
可以發現他先匯入setuptools裡的install物件
繼承這個物件然後在run()之中加入minimap2的安裝步驟
最後在setup的參數cmdclass加上'install' : MakeInstall
cmdclass如果沒有特別指定的話’install’的就會是預設的install
這個物件
|
|
不過這樣的寫法只適用在沒有其他python依賴套件需要安裝
因為我實際這樣寫發現這樣不會安裝我需要的套件
可能是因為這樣的繼承方式會沒有完全繼承所有的功能__init__()
這個初始化的步驟install
物件裏面應該有寫安裝依賴套件的函是在裏面
所以我改成以下寫法_post_install
就是我把客製化安裝的步驟寫在函式裡
打包專案上傳PyPI
我們之所以可以直接用pip install [pkg_name]
就可以安裝套件是因為開發者已經將套件打包好上傳到Pypi這個python套件拖管平台
他的網址實際上是https://pypi.org/simple
可以從pip指令看到這網址是預設值
正式上傳到PyPI之前官方有提供另一個測試的平台(test.pypi.org)讓你先上傳看看是不是能正常運作
版本號是在setup.py
中setup()
的參數version
修改
測試時的版本號可以隨意改1.0.0_test1
之類的
參考這篇打包套件基本上不會有問題
但自己實作還是有些事要注意
安裝時找不到依賴套件
打包和上傳的指令如下:
依賴的套件一定會在https://pypi.org/legacy/
但開發者不一定會在https://test.pypi.org/legacy/
也有相同的套件名和對應的版本號
所以上傳位置是test.pypi.org
通常都會顯示找不到依賴套件
這時候得要在pip install
加上額外的參數 --extra-index-url
|
|
https://packaging.python.org/en/latest/guides/using-testpypi/
當然如果你沒有任何依賴的套件,全部的程式碼都只有使用到預設的套件就不會有這種問題
有沒有撞名?
像我這次開發的套件名稱是juno
在PyPI已經有個名稱是Juno
我就上傳失敗了
即使他開頭是大寫也一樣,所以後來才改成bio-juno
也是一樣在setup()的參數name
修改
不過內部的套件名稱依然可以是juno
所以匯入套件時依然是import juno
以上都確認沒問題就可以用正式的版本號上傳到正式的平台了--repository-url
預設就是https://pypi.org/legacy/
,所以這參數就不用加了
|
|
完成後就可以直接用pip install [pkg]
,一個指令安裝套件了