Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Invalid wheel metadata when a direct-URL requirement has an environment marker

オープン
#4,158 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 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?

  1. The extra_requires path in python/private/py_wheel.bzl has the same missing-space problem: it emits

    metadata_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" under extra_requires = {"cuda": [...]}), this produces ...pkg.whl; extra == 'cuda' — the same invalid metadata. These lines pass through get_new_requirement_line in wheelmaker (which fixes them if the suggested fix above is applied, since the URL ends up in base and extra == '...' becomes extra), but only because rpartition(";") splits off the extra marker; the raw "%s; extra == '%s'" formatting should arguably also include the space for consistency.

  2. pip/uv accept name @ url; marker in 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

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

bazel-contrib/rules_python のほかの issue

bazel-contrib/rules_python の issue をすべて見る

似ている issue

Build System の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。