結論
setup.cfg1(やsetup.py2)のinstall_requires
とextras_require
、
pyproject.toml3のdependencies
とoptional-dependencies
についての話です4。
開発しているパッケージ(awesome_lib
)が依存するライブラリ(例:other_lib
)について5
- DON'T🙅♂️
other_lib==1.2.3
のように特定のバージョンをピンポイント📌で指定する - DO🙆♂️
- バージョン指定しない
other_lib
- 指定が必要な場合は範囲で
other_lib<2
- バージョン指定しない
目次
オススメ資料「パッケージングしよう」
みんなのPython勉強会(2022年1月)のaodagさん6発表「パッケージングしよう」7
アーカイブもあります(このトピックは19:01〜)
書き起こしてみます
ここ(install_requires)にバージョン指定できるんですけど、直接ここにバージョン固定して書かないでください。
使う人は、依存関係ガチガチに固定されても、他のライブラリとぶつかってインストールできなくなるだけなので、
最低このバージョン以上にしてなど、範囲指定で書きましょう
other_lib==1.2.3
のようにバージョンを固定すると、開発しているライブラリ(awesome_lib
)のユーザがインストールできないことがあるわけですね。
本記事執筆の経緯
ホッテントリで見かけたこちらの記事がきっかけです。
chat-hatenablog
、面白そう!👏
試してみたい〜
そんな私にとって、GitHubからインストールできるのは嬉しいです!
読んでいて、ピンポイントでバージョン固定されていることに気づいたので、以下のようにコメントしました。
Pythonで作ったCLIツールをGitHubから直接pipでinstallできるようにする方法 - $shibayu36->blog;「こうするともっと便利という情報があれば知りたい。」で浮かんだのは、install_requiresにはバージョンを直接指定せず、範囲指定するです。ref: <a href="https://www.slideshare.net/aodag/python77/26" target="_blank" rel="noopener nofollow">https://www.slideshare.net/aodag/python77/26</a>
2023/05/04 02:26
ですが、私の言葉足らずな感じがぬぐえず、今回記事としてアウトプットしました(ブックマークコメントの100文字は短すぎたのです)。
インストールするユーザからの見え方
install_requires
には例えば"openai==0.27.5"
と指定されています8。
「chat-hatenablog
を使いたい」ユーザが0.27.5以外のバージョンのopenai
をインストールしていた場合、環境構築でちょっと苦労することになってしまいます。
動作検証環境はこちら
- Python 3.10.9
- pip 23.1.2
- setuptools 67.7.2
OpenAIの開発が活発(執筆時点で最新は0.27.6)なので、私みたいなユーザは最新を使っていきます。
$ pip install git+https://github.com/shibayu36/chat-hatenablog.git openai==0.27.6 (略) ERROR: Cannot install chat-hatenablog==0.3.0 and openai==0.27.6 because these package versions have conflicting dependencies. The conflict is caused by: The user requested openai==0.27.6 chat-hatenablog 0.3.0 depends on openai==0.27.5 To fix this you could try to: 1. loosen the range of package versions you've specified 2. remove package versions to allow pip attempt to solve the dependency conflict ERROR: ResolutionImpossible: for help visit https://pip.pypa.io/en/latest/topics/dependency-resolution/#dealing-with-dependency-conflicts
これは「他のライブラリとぶつかってインストールできなくなる」を露骨に示すためのあまり現実的ではない例です。
現実的にありそうなのは以下でしょうか。
- openaiをインストール済み
- そこにchat-hatenablogを追加でインストール
$ pip install openai (略) Successfully installed aiohttp-3.8.4 aiosignal-1.3.1 async-timeout-4.0.2 attrs-23.1.0 certifi-2022.12.7 charset-normalizer-3.1.0 frozenlist-1.3.3 idna-3.4 multidict-6.0.4 openai-0.27.6 requests-2.30.0 tqdm-4.65.0 urllib3-2.0.2 yarl-1.9.2 $ pip install git+https://github.com/shibayu36/chat-hatenablog.git (略) Attempting uninstall: openai Found existing installation: openai 0.27.6 Uninstalling openai-0.27.6: Successfully uninstalled openai-0.27.6 Successfully installed PyYAML-6.0 SQLAlchemy-2.0.12 chat-hatenablog-0.3.0 dataclasses-json-0.5.7 html2text-2020.1.16 langchain-0.0.154 marshmallow-3.19.0 marshmallow-enum-1.5.1 mypy-extensions-1.0.0 numexpr-2.8.4 numpy-1.24.3 openai-0.27.5 openapi-schema-pydantic-1.2.4 packaging-23.1 pydantic-1.10.7 python-dotenv-1.0.0 regex-2023.5.5 tenacity-8.2.2 tiktoken-0.3.3 typing-extensions-4.5.0 typing-inspect-0.8.0
openai
のバージョンがchat-hatenablog
で指定された0.27.5まで下がります。
同時にインストールしない場合は後勝ちになるようですね。
openaiをアップデートすることはできます(ERRORと表示されますが、exit codeは0です)
$ pip install openai==0.27.6 (略) Installing collected packages: openai Attempting uninstall: openai Found existing installation: openai 0.27.5 Uninstalling openai-0.27.5: Successfully uninstalled openai-0.27.5 ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts. chat-hatenablog 0.3.0 requires openai==0.27.5, but you have openai 0.27.6 which is incompatible. Successfully installed openai-0.27.6
この動きを全員が気にするわけではないと思いますが、
- setup.pyの
install_requires
は依存ライブラリのバージョンを固定する用途では使わない慣習という理解 - 開発者が少し手を動かすだけで上記の動きは取り除ける
という2つの理由からinstall_requires
には"openai"
(バージョン指定しない)という書き方が私からの提案となります。
私の考え:パッケージのinstall_requires
は環境の再現に使うrequirements.txt
とは用途が違うのではないか
install_requires
やextra_requires
- パッケージのユーザや開発者に一緒にインストールしてほしい依存ライブラリを(必要であれば範囲で)指定する
requirements.txt
など- Pythonの環境再現に使う
- パッケージの開発者間で揃えたい場合は
pip install -r requirements.txt
で環境構築する運用になると考えます
これは私がPythonで開発する機会が多いがために馴染んでいる考え方にすぎず、他の言語のパッケージ管理からするとちょっと異質に見えるかもしれませんね。
- https://setuptools.pypa.io/en/latest/userguide/declarative_config.html↩
-
setup.py
はどうしても必要ではないなら避けよう(setup.cfgかpyproject.tomlを使おう)という内容を知りまして、カッコ書きにしています。ref:https://setuptools.pypa.io/en/latest/userguide/quickstart.html#setup-py↩ - https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html↩
- aodagさんのトーク(19:01の少し前のところ)との関連でいうと、pyproject.tomlではめちゃめちゃわかりやすくなってますね↩
- パッケージとライブラリは同じ意味という認識です。この記事では開発するのはパッケージ、パッケージが依存するのはライブラリという語用にしてみました↩
- aodagさんはPyCon JPでもPythonのパッケージングについて何度も発表されており、非常に信頼できる情報筋と認識しています↩
- 過去のパッケージング関連記事でも参照しました。Pythonでリソースファイルと一緒にパッケージをインストールするための設定値(📣MANIFEST.inが必要です) - nikkie-ftnextの日記↩
- https://github.com/shibayu36/chat-hatenablog/blob/04b4486e830380a294867e9dcde010989417aa48/setup.py#L23↩