python打包發佈pypi踩坑記(最新貼心版本,認真對待自己的庫)

在之前這個實現json比較的庫的帖子裏,我把庫上傳pypi的時候,相當坑。而且pypi有個特點,就是你一旦弄錯了,就不能刪除原來的名字(但可以刪庫,也可以更新版本,就是不能替換)。所以上傳時應該儘量謹慎。

1. 註冊pypi的賬號

訪問pypi.org並點擊register(有部分網絡pypi訪問速度較差,可能發生上傳或下載失敗的情況,請換個網絡環境,或者自備代理)。可以使用QQ郵箱,它會要求你的郵箱驗證。
在這裏插入圖片描述
如果你想使用pypitest來測試發佈,也可以同時註冊pypitest。

2. 處理路徑。你的項目應該呈現這樣的結構:

在這裏插入圖片描述
其中裏層的是你要上傳的包。而外層來寫setup.py和readme。這兩個將在後面介紹。dist是打包發佈後自動生成的文件夾,裏面有打成的包(python編譯exe的同學應該對此不陌生,因爲編譯exe的輸出路徑一般也在dist裏面),而MANIFEST也是自動生成。所以我們着重要做的就是__init__.py,還有reademe和setup.py這三個文件的編寫。

3. 代碼規範化。

在打包前應該注意一些事情。

  • 整個代碼中,除了if __name__ == "__main__"可以包含打印輸出、調試的部分之外,其他地方都應該只有函數、類、全局變量等的定義。導入時不應該出現print等副作用。除非你確實希望如此例外。
  • 在例子中,json_compare是我實現功能的庫,而test_json_compare是測試用例。其中__init__.py文件則是python中將一個目錄識別爲包必不可少的文件,是訪問包的入口。在內應導入所有需要暴露的類或函數。爲兼容,最好如下圖使用相對路徑導入。(如果不是一個包,普通目錄內這樣寫IDE會報錯)
    在這裏插入圖片描述
  • 版本兼容。考慮你的代碼究竟適合於哪些版本,並小心測試通過。在我的例子中,我支持了python2.x和3.x,所以特意使用six模塊進行適配,有些地方需要去針對不同版本做不同的操作。另外,要考慮平臺的兼容性。所以每個文件的頭兩行應該使用標準的方法來寫,避免放到Linux的機器上不識別。
#!/usr/bin/env python
# coding: utf-8

在這裏插入圖片描述
在這裏插入圖片描述

  • 編寫註釋和類型提示。尤其是針對對外暴露的方法編寫註釋。
    使用一對三雙引號,是python中函數和類註釋文檔的規範。函數寫完後輸入三個",pycharm會自動幫你形成文檔骨架。:param表示參數,隨後寫參數的類型,最後是參數名,比如參數a的類型就是str/unicode/list/tuple/dict中的一種(實際上這顯然是針對python2,3裏面應該對應bytes,但這樣寫無妨),而參數ignore_list_seq類型則是bool。return下面也要寫明返回值的類型。
    這些類型不是必需的,但是有諸多好處。諸如Pycharm這樣的IDE會自動針對返回值和參數提供類型提示和方法聯想,比如若你使用了這個函數的返回值變量,那只有在返回值被註釋爲str類型或者IDE能自己判斷出返回類型時,纔會給你提供.join等方法的聯想。同時,當用戶傳錯了參數類型時,也會被IDE提示警告,從而引起用戶警覺。這類動態語言應該非常注意類型的校驗,否則容易發生幽靈bug,且代碼的可讀性,可調實性都會變差。
    在這裏插入圖片描述

4. 編寫readme.md文檔

一個項目能做什麼,很大程度取決於文檔。要想類似下圖這樣,給你的項目在pypi頁面上寫個好的介紹,你需要準備項目的介紹文檔。 強烈推薦給自己的項目準備文檔。 我們這裏使用我們熟悉的markdown。但需要注意的是,要麼你安裝twine且升級pip,配置新的選項,否則pypi不支持markdown,它支持的是rst文件(這個非常坑,如果搞錯了格式,它也不會報錯,不會有任何警告,就只是文檔無法展示而已)。好在markdown和rst可以轉換。我們稍後會用代碼將其轉換。
在這裏插入圖片描述
例如這上面的文檔,上傳後會產生如下效果
在這裏插入圖片描述

5. 準備轉換文檔的工具

需要安裝一個轉換文檔格式的模塊

pip install pypandoc

安裝好後,我在其他項目源碼中看到過類似的代碼,但是總是發現文檔無法展示。後來
在這裏插入圖片描述
去掉了上面的except,查看報錯信息,結果發現pypandoc是需要依賴pandoc這個程序的,它只是pandoc的python接口。於是又去安裝pandoc。在官網的這個鏈接可以下載安裝程序。https://www.pandoc.org/installing.html安裝比較簡單。不過裝好以後要配置環境變量。將下面圖上的路徑加入到path裏。
在這裏插入圖片描述
在這裏插入圖片描述
保存後,重新打開cmd,驗證能夠通過where找到就算成功
在這裏插入圖片描述

6. 編寫setup.py文件

仍然記得之前的規範(編碼、python解釋器路徑等),示例如下:

#!/usr/bin/env python
# coding: utf-8
from distutils.core import setup
from os import path
this_directory = path.abspath(path.dirname(__file__))

try:
    import pypandoc
    long_description = pypandoc.convert('README.md', 'rst')
except:
    long_description = ""

setup(
    name='jsoncomparedeep',
    version='1.12',
    description='A recursive Json comparing library that handles list orders and fuzzy types',
    author='Rainy Chan',
    author_email='[email protected]',
    url='https://rainydew.blog.csdn.net/article/details/93904318',
    packages=['json_compare'],
    install_requires=['six>=1.12.0'],
    keywords='json compare comparison order unicode fuzzy',
    long_description=long_description,
    python_requires=">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
)

一些注意點解釋如下

  • 使用path.abspath來活化路徑,否則用戶在pip下載安裝你的包時,會被紅色字體報錯警告(大部分時候仍然可以安裝),影響用戶體驗。
  • long_description這裏必須使用try處理。否則用戶在pip安裝時,也會執行此setup.py。若用戶機沒有pypandoc,或者雖然有但環境變量裏找不到pandoc.exe,則都會報錯導致安裝失敗。這一句話的用途是將markdown文檔轉換爲rst格式文檔並上傳。
  • name請在https://pypi.org先做搜索。不能和pypi上已有的項目重名,否則會上傳失敗。不要使用中文名。同時取名請慎重,因爲一旦取好將不能再修改,只能取新的名字。這裏有個小技巧,就是比如我做的是jsoncompare,但pypi上已經有了同樣名字的項目,那麼我如果要被搜索到,我應該取jsoncomparedeep這樣的後綴,而非看起來更自然的deepjsoncompare。因爲pypi會從開頭來匹配,輸入json compare,可以搜到jsoncomparedeep,卻搜不到後者。
  • version可以從0.1開始,也可以是三段的版本號比如0.1.0。當你更新升級了你的庫以後,你只能修改version而不能修改名字來上傳,否則pip install -U將不起作用。而且version只能越來越大。比如1.12之後的下一個版本只能從1.13開始。要小心的是,一個version一旦傳上去了,就不能再修改。你可以刪除,但即便刪除,這個版本號也不能再使用,只能使用下一個版本號。pypi以此來保障包的一致性,即用戶使用pip下載同樣名字和同樣的版本,不會下載到實際上不相同的包。如果你的包發現了嚴重bug,則應該儘快刪除它並上傳新版本。
  • url是你的項目主頁路徑
  • packages裏應該取圖上目錄中,你的包的文件夾名(和setup.py同級的文件夾)。大的項目有多個文件夾,則列表寫多個目錄。
  • install_requires這個非常重要,注意了,不是有些文章或者demo裏的requires!!裏面寫你需要依賴的庫(和其版本)的情況。只寫非官方庫。我的這個庫引用了json re sys traceback和six,只有用於python2/3兼容的庫six是三方庫,所以我這裏只寫了six。最好要求指定版本號。如果你不清楚版本,可以用pip --list命令去查看你當前使用的版本。這一項的目的是能讓pip自動處理依賴。比如用戶安裝我的pip install jsoncomparedeep,且系統發現這個用戶還沒有安裝six庫,就會自動一併安裝six庫,這樣用戶安裝好我的庫以後,就不會在import的時候報錯。這個地方十分坑,我開始寫的是文檔裏的requires,後來看了flask的源碼的setup.py,才發現要這麼寫才能認得。
  • long_description就是展示在首頁的文檔。而description會在搜索庫的時候就展示,所以應該簡練清晰的表明庫的功能。例如在這裏插入圖片描述
  • python_requires可以防止用戶使用不兼容的python版本來安裝你的庫。例如我上面的公式,則是要求用戶的python版本爲2.6~2.7,或3.5以上。

7. 建立 .pypirc 文件

對於Linux用戶,直接在家目錄下建立;對於windows用戶,在運行-cmd裏默認指向的路徑下建立。windows系統會弱智到不允許你建立一個以英文.開頭的文件。可以運行cmd,並使用這樣的命令
在這裏插入圖片描述
回車後即可建立這個文件,請用notepad++之類的打開(不允許BOM,所以千萬不要用記事本去修改)。編輯配置如下並保存。其中username和password寫你在pypi和pypitest的用戶名和密碼。如果你不上傳pypitest,下面的可以不要。最好以unix換行符(LF)作爲文件的換行標誌。
在這裏插入圖片描述

8. 上傳到pypi

確保你的python.exe在環境變量內,否則需要提供python.exe的完整路徑。
在setup.py的目錄下打開cmd(可以pycharm裏setup.py右鍵-在終端內打開)。然後輸入

python setup.py sdist upload -r pypi

並回車,命令行提示200,即上傳成功(如果是上傳pypitest則命令改爲pypitest)。隨後請在pypi內查看自己的包,觀察首頁展示,並測試下載和安裝。尤其是推薦在標準版python(沒有三方庫)的虛擬機等處測試安裝。
在我的ubuntu虛擬機上測試安裝
在這裏插入圖片描述
可以看到能夠自動安裝six模塊,意味着能自動處理依賴。
然後在python中嘗試導入並執行成功。
在這裏插入圖片描述
enjoy~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章