python / python/importlib_metadata
API incompatibility with `importlib.metadata` (or at least the API is not type-safe?)
まだ誰も着手していません。
- 主要言語
- Python
- スター
- 142
- フォーク
- 97
- PR マージ指標
- 30日以内にマージされた PR はありません
説明
When 3rd-party MetaPathFinder are implemented using importlib.metadata, the return types in importlib_metadata are not respected, which causes the API to behave in an unexpected way (with unexpected errors).
This is an example similar to the one identified in https://github.com/pypa/pyproject-hooks/pull/195#issuecomment-2088695300 and https://github.com/pypa/setuptools/issues/4338:
mkdir -p /tmp/stash/private_path/_test-0.0.1.dist-info
cat <<EOF > /tmp/stash/private_path/_test-0.0.1.dist-info/METADATA
Name: _test
Version: 0.0.1
EOF
cat <<EOF > /tmp/stash/private_path/_test-0.0.1.dist-info/entry_points.txt
[_test.importlib_metadata]
hello = world
EOF
cat <<EOF > /tmp/stash/install_finder.py
import sys
from importlib.machinery import PathFinder
from importlib.metadata import DistributionFinder, MetadataPathFinder
class _ExampleFinder:
def __init__(self, private_path):
self.private_path = private_path
def find_spec(self, fullname, _path, _target=None):
if "." in fullname:
# Rely on importlib to find nested modules based on parent's path
return None
# Ignore other items in _path or sys.path and use private_path instead:
return PathFinder.find_spec(fullname, path=self.private_path)
def find_distributions(self, context=None):
context = DistributionFinder.Context(path=self.private_path)
return MetadataPathFinder.find_distributions(context=context)
sys.meta_path.insert(0, _ExampleFinder(["/tmp/stash/private_path"]))
EOF
cd /tmp/stash/
python3.8 -m venv .venv
.venv/bin/python -m pip install -U importlib-metadata
.venv/bin/python
>>> import install_finder
>>> from importlib_metadata import distribution
>>> distribution("_test").entry_points.select(group="_test.importlib_metadata")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'select'
The expected behaviour as per API documentation would be:
>>> distribution("_test").entry_points.select(group="_test.importlib_metadata")
EntryPoints((EntryPoint(name='hello', value='world', group='_test.importlib_metadata'),))
It seems that the origin of this problem is a little "lie" in the API definition:
Instead of
importlib_metadata.Distribution.discover(...) -> Iterable[importlib_metadata.Distribution]
what actually happens is:
importlib_metadata.Distribution.discover(...) -> Iterable[importlib_metadata.Distribution | importlib.metadata.Distribution]
and that propagates throughout the whole API.
I haven't tested, but there is potential for other internal errors too, if internally importlib_metadata is relying that the objects will have type importlib_metadata.Distribution to call newer APIs.
It is probably worthy to change the return type of importlib_metadata.Distribution.discover(...) to Iterable[importlib_metadata.Distribution | importlib.metadata.Distribution] and then run the type checkers on the lowest Python supported (I suppose Python 3.8), to see if everything is OK.
It also means that consumers of importlib_metadata cannot rely on the newer APIs (unless they are sure that 3r-party packages installed in their environment are not using importlib.metadata).
コントリビューションガイド
このリポジトリのコントリビューションガイドは索引されていません
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
まず、カスタム MetaPathFinder と issue に記載されている Python 3.8 環境を使って、ドキュメント化された例を再現します。Distribution.discover と関連する discovery フローを調査し、その後、サポート対象のベースラインに対して型チェッカーを実行して、サードパーティの importlib.metadata ディストリビューションとその entry_points の結果が一貫して扱われることを確認します。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- python
- 領域
- api, backend-api-design
- issue の種類
- バグ
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 活発さ
- 停滞
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 35/100