最熟悉的陌生腳本 : setup.py
每個 Open Source 的 Python 套件都會有個 setup.py
,看了它也不下幾十次了,但每次要寫,就是會忘記怎麼寫 (甚至還有個 repo 就專為 setup.py
寫範例)。在學會 pip
之後,甚至連寫它都懶得寫,直接用 pip
取代它:
pip freeze > requirements.txt
pip install -r requirements.txt
# 看來很熟悉吧?
直至今日,我才在這篇文章裡了解到 setup.py
與 requirements.txt
是兩種不同的概念,沒有誰取代誰的事情。
在 setup.py
裡,大多定義了以下內容:
- Who : 到底是誰寫了這套件 (a.k.a 有 bug 誰要修)
- What : 這套件在做啥
- HOW : 這套件需要其他哪些套件才能運作
其中我覺得第三點是 setup.py
最重要的工作。
從範例裡可以看到 install_requires
這個關鍵字,用來定義所需要的額外套件。之前看過不少 Open Source 套件會這樣寫 setup.py
:
with open('requirements.txt') as fid:
requires = [line.strip() for line in fid]
...setup(
...,
install_requires=requires,
...
)
之前我也是有樣學樣,自以為這樣我就只要用 pip
管理,就可以自動同步 setup.py
的相依問題。但這是不對的。
這裡我擷取官方文件裡的內容:
install_requires
is a setuptoolssetup.py
keyword that should be used to specify what a project minimally needs to run correctly. When the project is installed by pip, this is the specification that is used to install its dependencies.
簡單的來說,setup.py
的 install_requires
是用來表達你的套件被使用時所需要的套件,而 requirements.txt
是用來表達你具體的環境是如何。
說來有點而繞口,但這差別是什麼?
這裡我偷用了這篇 blog 的內容來說明。 譬如說你在install_requires
裡寫說需要 numpy
,就像是 Python 的 duck typing 一樣,意思是你的套件需要一個看起來像 numpy
的套件就好了,你並不在意實際上這 numpy
是誰,只要它看起來像個 numpy
就好。
但在 requirements.txt
裡 (或者 pip freeze
) 的意義就不同了,這代表了你需要特定某個 numpy
才能重現你的環境。
我想之所以會混淆這兩個的差別,是因為 pip
跟 requirements.txt
的時候,你也可以把 requirements.txt
裡所有的版本號去除, pip
一樣可以運作,就好像你不在意版本一樣。我覺得這應該是 pip
設計不好的地方,如果 pip
限制你在 -r
的時候強制鎖版號,應該就不會有這樣的混淆了。
一切都是為了開發
這樣的差別或許對眾多使用者來說,並不是很重要,但對開發者而言,是有實質上的差別的。
想像你正在開發兩個套件,兩個套件可以獨立使用,但彼此相依。這時候你可能會希望開發的時候兩個套件分開開發、發佈時同時發佈。這時候,它們個別的版本號就至關重要。身為開發者,你會想要知道“具體”來說它們是誰,而不是只是個概念上像誰的東西。
所以在個別的 setup.py
裡,兩個套件會寫下彼此的套件名稱,但在 pip freeze
卻是給你具體的套件資訊。這樣當你有一天結束兩個套件的開發,從開發者變成使用者時,不需要再被這些煩人的版號所拘束,可以比較方便的使用它。
pipenv >= pip + virtualenv
數學系的老毛病,不等式是我們的最愛。 pipenv
目前我用起來的感覺真的還蠻不錯的,在一般的狀況下確實比用 pip
跟 virtualenv
還爽。
具體內容,我想就留到下一篇再寫吧,我累了 XDD
有興趣的人,可以先到官方 repo 挖寶。
References
- https://github.com/pypa/pipenv
- https://github.com/pypa/pipenv/issues/209
- https://packaging.python.org/discussions/install-requires-vs-requirements/#requirements-files
- https://caremad.io/posts/2013/07/setup-vs-requirement/
- https://stackoverflow.com/questions/12518499/pip-ignores-dependency-links-in-setup-py