節日問候!
在我開始之前,我想先說清楚我將要解釋的是些“竅門”。他們不是“最好的做法”,至少在一種情況下是不可取的。
說到不可取的做法,我會適時寫一個“setup.py陷阱”的博文,這都是我相信你不會在setup.py模組做出的事情。
竅門
這些竅門讓我使用python做打包管理變得更簡單。在你完善他們之前,我建議你至少有些關於建立新包的基本經驗。學python打包的兩種方法是New Library Sprint (初級)和 Python Packaging User Guide (高階些)。
‘python setup.py publish’
一切都是從這裡開始的。一天我在看湯姆的程式碼時發現python setup.py publish命令在Django Rest Framework裡的 setup.py模組裡面。它像這樣:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# setup.py import os import sys # I'll discuss version tricks in a future blog post. version = "42.0.0" if sys.argv[-1] == 'publish': os.system("python setup.py sdist upload") os.system("python setup.py bdist_wheel upload") print("You probably want to also tag the version now:") print(" git tag -a %s -m 'version %s'" % (version, version)) print(" git push --tags") sys.exit() # Below this point is the rest of the setup() function |
用這種方法太讚了,我不需要去查詢那有些晦澀的python setup.py sdist upload命令,或是真的很讓人困惑的python setup.py bdist_wheel upload命令了。取而代之的是,當要把包釋出在PyPI上時,我只需要打下:
1 |
$ python setup.py publish |
好記多了!
‘python setup.py tag’
湯姆的python setup.py publish指令的問題在於,他強迫我去打出git tag命令。好吧,誠實些,他讓我複製/貼上我螢幕上的輸出。因此,全靠我自己,我“發明”了python setup.py tag 指令:
1 2 3 4 5 6 |
# setup.py if sys.argv[-1] == 'tag': os.system("git tag -a %s -m 'version %s'" % (version, version)) os.system("git push --tags") sys.exit() |
很漂亮,哈?現在我不需要去記住那麼多模糊的git命令。我就得到了短版python setup.py publish命令:
1 2 3 4 |
if sys.argv[-1] == 'publish': os.system("python setup.py sdist upload") os.system("python setup.py bdist_wheel upload") sys.exit() |
當我需要做一個版本時,我用我的程式碼,然後打出:
1 2 |
$ python setup.py publish $ python setup.py tag |
我為什麼不合並那些程式碼?嗯,你不可以把“RC1”或“-alpha”用作你PyPI的版本名稱。分離這些命令,我可以對我的包的釋出有更精細的掌控。我被鼓勵用alpha、beta,還有在git tag釋出參與者,而不是正式的PyPI釋出。
‘python setup.py test’
我很確定我的一些讀者在這個竅門中會遇到很嚴重的問題。事實上,依據管理python包的基礎建設的人的迴應,這會在我接下來的“陷阱”博文中講。
那麼然後……
我喜歡py.test。我曾寫過關於使用py.test的部落格。我試著在各處用它。然而,我真的不是必須用python setup.py test的狂熱分子。我感覺到用py.test不舒服的那一刻是它讓我在setup.py中新增特殊類時。
不幸的是,有另一種方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
if sys.argv[-1] == 'test': test_requirements = [ 'pytest', 'flake8', 'coverage' ] try: modules = map(__import__, test_requirements) except ImportError as e: err_msg = e.message.replace("No module named ", "") msg = "%s is not installed. Install your test requirments." % err_msg raise ImportError(msg) os.system('py.test') sys.exit() |
只意味著我要新增一個簡單的程式碼來用py.test和python setup.py test:
1 |
$ python setup.py test |
理論上,可以執行pip install命令安裝缺少依賴包,或者從requirements檔案中呼叫。但是,由於這是“竅門”,我想讓它保持簡潔好用。如果我用這個得到了足夠的好結果,我會更新這個包括缺少要求的pip呼叫的例子。
注意:這不是說我不用tox。實際上,我用tox來呼叫我那一版本的python setup.py test。
subprocess模組怎麼樣?
有些人會問,“你為什麼不利用子程式庫來用這些shell命令呢?”
我的答案是,“因為,如果我殺雞還需要用宰牛刀的話,未免太過了。”對於這些簡單的竅門,os.system()函式就很夠用了。
為什麼不直接用Makefile?
我一開始在Mac OSX和Linux上程式設計,我的很多開源包使用Windows。感謝AppVeyor,我正不斷測試在那環境中的程式碼。實際上,我會給Windows使用者改進我的“竅門”。
陷阱!
2015年初會發布“陷阱”部落格,敬請期待
Updates
- 2014/12/21 – Added a note about using tox.
- 2014/12/21 – Added a note about Makefile and Windows