Invalid wheel metadata when a direct-URL requirement has an environment marker
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 初心者へのやさしさ
- 78/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- python
- 領域
- build-system
調査の方向性
tools/wheelmaker.py の get_new_requirement_line から始め、python/private/py_wheel.bzl の extra_requires の処理を確認してください。提供された BUILD.bazel の例と pip install --dry-run を使って問題を再現してください。生成された wheel メタデータが、extra_requires のエントリを含め、環境マーカー付きの direct-URL 要件を受け入れれば完了です。
索引モデルが issue の本文から書いたものです。
説明
🐞 bug report
Affected Rule
The issue is caused by the rule: py_wheel (specifically get_new_requirement_line in tools/wheelmaker.py, and the extra_requires handling in python/private/py_wheel.bzl)
Is this a regression?
No — the bug was introduced together with URL-requirement support in wheelmaker (PR #3569). Direct-URL requirements with environment markers have never produced valid wheel metadata.
Description
When a py_wheel requires (or a line in requires_file) is a PEP 508 direct-URL requirement with an environment marker, e.g.
somepkg @ https://example.com/wheels/somepkg-1.0-none-none-linux_x86_64.whl ; sys_platform == 'linux'
wheelmaker re-serializes the requirement in get_new_requirement_line as:
base = f"Requires-Dist: {req.name}{req_extra_deps}{req_spec}" # ends with the URL
...
return f"{base}; {req.marker}" # no whitespace before ';'
producing a METADATA line without whitespace before the ; marker separator:
Requires-Dist: somepkg @ https://example.com/wheels/somepkg-1.0-none-none-linux_x86_64.whl; sys_platform == 'linux'
That is invalid PEP 508. Per the spec, whitespace after a URL is mandatory since ; is a valid URI character (sub-delims), so a strict parser greedily consumes whl; into the URL and then fails. pip rejects the wheel at install time:
ERROR: Requested urlmarker==0.1 from file:///.../urlmarker-0.1-py3-none-any.whl has invalid metadata: Expected semicolon (after URL and whitespace) or end
somepkg @ https://example.com/wheels/somepkg-1.0-none-none-linux_x86_64.whl; sys_platform == 'linux'
Note that wheelmaker strips extra whitespace via Requirement(...) round-tripping, so there is no way to emit valid metadata for URL+marker requirements through py_wheel without patching wheelmaker.
For non-URL requirements (stim~=1.16.0; sys_platform != 'linux') the missing space happens to be harmless since the grammar allows version_end wsp* ';', so this only breaks direct URLs.
🔬 Minimal Reproduction
# BUILD.bazel
load("@rules_python//python:packaging.bzl", "py_wheel")
py_wheel(
name = "wheel",
distribution = "urlmarker",
version = "0.1",
requires = [
"somepkg @ https://example.com/wheels/somepkg-1.0-none-none-linux_x86_64.whl ; sys_platform == 'linux'",
],
)
bazel build //:wheel
pip install --dry-run bazel-bin/urlmarker-0.1-py3-none-any.whl
# => ERROR: ... has invalid metadata: Expected semicolon (after URL and whitespace) or end
(The URL does not need to resolve — metadata validation fails before pip ever fetches it.)
🔥 Exception or Error
ERROR: Requested urlmarker==0.1 from file:///.../urlmarker-0.1-py3-none-any.whl has invalid metadata: Expected semicolon (after URL and whitespace) or end
somepkg @ https://example.com/wheels/somepkg-1.0-cp312-cp312-macosx_15_0_arm64.whl; sys_platform == 'darwin'
Suggested fix
Emit a space before ; in all branches of get_new_requirement_line — valid for every requirement type and required for URLs:
if req.marker:
if extra:
- return f"{base}; ({req.marker}) and {extra}"
+ return f"{base} ; ({req.marker}) and {extra}"
else:
- return f"{base}; {req.marker}"
+ return f"{base} ; {req.marker}"
elif extra:
- return f"{base}; {extra}"
+ return f"{base} ; {extra}"
(Note extra may itself be a marker expression such as extra == 'cuda', and base may end in a URL here too when extra_requires entries use direct URLs — see below.)
🌍 Your Environment
Operating System:
Ubuntu (Linux x86_64)
Output of bazel version:
Bazelisk version: v1.29.0
Build label: 9.2.0
Build target: @@//src/main/java/com/google/devtools/build/lib/bazel:BazelServer
Build time: Mon Jul 13 18:15:04 2026 (1783966504)
Build timestamp: 1783966504
Build timestamp as int: 1783966504
Rules_python version:
2.3.3 (still present on main at the time of writing)
Anything else relevant?
-
The
extra_requirespath inpython/private/py_wheel.bzlhas the same missing-space problem: it emitsmetadata_contents.append( "Requires-Dist: %s; extra == '%s'" % (requirement, option), )If an extra's requirement is a direct URL (e.g.
"somepkg @ https://example.com/pkg.whl"underextra_requires = {"cuda": [...]}), this produces...pkg.whl; extra == 'cuda'— the same invalid metadata. These lines pass throughget_new_requirement_linein wheelmaker (which fixes them if the suggested fix above is applied, since the URL ends up inbaseandextra == '...'becomesextra), but only becauserpartition(";")splits off the extra marker; the raw"%s; extra == '%s'"formatting should arguably also include the space for consistency. -
pip/uvacceptname @ url; markerin requirements files, which masks the issue during development — the failure only surfaces when installing the built wheel, because wheel metadata is validated strictly.
- 主要言語
- Starlark
- スター
- 688
- フォーク
- 724
- 平均マージ
- 1日 20時間
- マージ済み PR(30日)
- 45
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
bazel-contrib/rules_python のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
bazel-contrib/rules_python#4201 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
bazel-contrib/rules_python#4164 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
go:embed stdlib_list.txt file in gazelle/python/std_modules.go is missing対応中かも @udaya2899 が 7 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
bazel-contrib/rules_python#3821 ·
メンテナーはふだん 1 日以内に返信
-
難易度 5/5 1週間以上 初心者へのやさしさ 28/100
bazel-contrib/rules_python#4218 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
type: toolchain
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
bazel-contrib/rules_python#4216 · コメント 5 件 · リアクション 1 件 ·
メンテナーはふだん 1 日以内に返信
bazel-contrib/rules_python の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
graphql-hive/graphql-modules#2686 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
メンテナーはふだん 3 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
メンテナーはふだん 5 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 90/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 79/100
QymIs-Tech/QymCAD#99 ·
メンテナーはふだん 1 日以内に返信