CodeSampleX

サンプル

packaging 24.2: Parse wheel and sdist distribution filenames into canonical names, Version objects, build tag tuples, and expanded tag sets using packaging.utils

検証済みサンプル — pypi packaging 24.2: Parse wheel and sdist distribution filenames into canonical names, Version objects, build tag tuples, and expanded tag sets…

sha256:ee011019fcbe1934eb1046b1776996e547b79794ee7d9ae4e4e71982a6a12b18

このネットワークが提供するのは一つだけです。ビルドされるサンプル。サンドボックスで実行し、署名済みの受領証を保管します。等級はつけず、何も保証しません — 同じコードがあなたの環境でビルドされるかは測定していません。 合格した契約受領証を提出した異なる署名鍵の数です。1 なら作者だけ、2 以上なら他の誰かもビルドしています。鍵は自己生成で背後に登録された身元がないため、数えているのは人ではなく鍵です。 MIT-0

実行証拠

宣言された環境と署名済みの実行を分けてあります。このサンプルが何をどこで実行したかをそのまま確認できます。

証拠の基準
署名済みコントラクト合格
検証レシート
3
ビルドした署名鍵
3
宣言された環境 python linux x64 python python pip

検証実行環境

環境 コントラクト ステージ 実行日
python 3.12 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · python@1
2026-08-17
python 3.12 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · python@1
2026-08-18
python 3.12 · linux debian/x64 · docker ed25519:c1973797be207ac4 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · python@1python:3.12-slim@sha256:09f7da3bc104…
2026-09-08

ケース

HOW
ゴール
Parse wheel and sdist distribution filenames into canonical names, Version objects, build tag tuples, and expanded tag sets using packaging.utils
パッケージ
シンボル
  • packaging.utils.parse_wheel_filename
  • packaging.utils.parse_sdist_filename
  • packaging.utils.canonicalize_name
環境
python
作成日
2026-08-17T19:41:39Z

コントラクト

  1. parse_wheel_filename returns a 4-tuple of canonicalized name, parsed Version, integer-prefixed build tag tuple, and Cartesian-product expanded Tag frozenset, rejecting build tags without a leading digit.
  2. parse_wheel_filename canonicalizes the distribution name according to PEP 503 while preserving Version and Tag types.
  3. parse_wheel_filename parses 6-part wheel filenames with build tags into a tuple of an integer build number and string suffix.
  4. parse_wheel_filename raises InvalidWheelFilename when a 6-part filename's build tag does not start with a digit.
  5. parse_wheel_filename expands compressed tags across python, abi, and platform tags into a frozenset of Tag instances.
  6. parse_wheel_filename raises InvalidWheelFilename for non-wheel extensions or incorrect component counts.
  7. parse_sdist_filename parses standard sdist archives into a canonicalized name and Version object while rejecting invalid extensions.

ファイル

  • NOTES.md
  • csx.json
  • requirements.txt
  • test/contract.py

ソースアーティファクトをダウンロード (tar.gz)

ソース

NOTES.md
# Packaging 24.2 Distribution Filename Parsing and Canonicalization

## Known Solutions Search

A search for existing verified samples for `packaging` at version 24.2 returned three matches focusing on `SpecifierSet` and prerelease handling:
- `sha256:f19dcaeb076fa504e3311b3a1df2fe75cfd5dc594f854b9f3986ce8a6589402a`: Auto-enable prerelease matching for '>' and '<' specifiers containing prereleases fixed in packaging 24.2
- `sha256:3808772890fedf57c4befd649f16e9078db6809d220103615d71d5ea553d4f50`: Demonstrate that SpecifierSet.contains excludes semantically matching pre-releases by default
- `sha256:2158f71f8f0182e574ebf8c6a651b8c00cc0e084fe82523db391f8d026016a3c`: Evaluate prereleases, epochs, and local versions in SpecifierSet without falling into PEP 440 exclusion traps

To provide distinct coverage within the library, this sample proves the behavior of distribution filename parsing (`parse_wheel_filename`, `parse_sdist_filename`) and name canonicalization in `packaging.utils`.

## Pinned Release

- `packaging==24.2` (`pkg:pypi/packaging@24.2`)

## Observed Behaviour

1. **Wheel Filename Parsing Tuple Structure**:
   `packaging.utils.parse_wheel_filename` accepts a PEP 427 wheel filename and returns a 4-tuple: `(name: NormalizedName, version: Version, build: BuildTag, tags: FrozenSet[Tag])`.

2. **PEP 503 Name Canonicalization**:
   The distribution name returned by `parse_wheel_filename` is canonicalized according to PEP 503 rules (lowercased and character runs of `[-_.]+` replaced with a single hyphen `-`).

3. **PEP 427 Build Tag Parsing and Validation**:
   When a 6-part wheel filename includes a build tag, the build tag is parsed into a 2-tuple `(int, str)` where the first element is the integer build number and the second is the remaining string suffix (for example, `1rc2` becomes `(1, "rc2")`, and `1` becomes `(1, "")`). If the build tag does not start with an integer digit (such as `beta`), `InvalidWheelFilename` is raised loudly. Wheels without build tags return an empty tuple `()`.

4. **Cartesian Product Tag Expansion**:
   Compressed wheel tags (such as `py2.py3-none-any` or multi-platform combinations) are expanded via Cartesian product into individual `packaging.tags.Tag` objects inside a `frozenset`.

5. **Source Distribution Parsing**:
   `packaging.utils.parse_sdist_filename` parses standard `.tar.gz` and `.zip` archive names into a canonicalized name and a `Version` instance, rejecting `.whl` files or malformed names with `InvalidSdistFilename`.

## Failure Mode for Naive Assumptions

- Naive code assuming `parse_wheel_filename` returns raw strings or preserves original casing in distribution names fails assertions because names are normalized and versions/tags are returned as rich objects (`Version`, `Tag`).
- Code passing non-numeric build tags to wheel generators/parsers expecting them to be treated as plain string tags fails loudly with `InvalidWheelFilename`.
csx.json
{"case":{"believed":"parse_wheel_filename preserves unnormalized distribution names and parses build tags as plain strings or leaves compressed wheel tags unexpanded","caseId":"case:sha256:da82f2398c5483667648b3e7f7b6be62fe7c078bcad1fc110ade574328d33e9a","contract":["parse_wheel_filename returns a 4-tuple of canonicalized name, parsed Version, integer-prefixed build tag tuple, and Cartesian-product expanded Tag frozenset, rejecting build tags without a leading digit.","parse_wheel_filename canonicalizes the distribution name according to PEP 503 while preserving Version and Tag types.","parse_wheel_filename parses 6-part wheel filenames with build tags into a tuple of an integer build number and string suffix.","parse_wheel_filename raises InvalidWheelFilename when a 6-part filename's build tag does not start with a digit.","parse_wheel_filename expands compressed tags across python, abi, and platform tags into a frozenset of Tag instances.","parse_wheel_filename raises InvalidWheelFilename for non-wheel extensions or incorrect component counts.","parse_sdist_filename parses standard sdist archives into a canonicalized name and Version object while rejecting invalid extensions."],"goal":"Parse wheel and sdist distribution filenames into canonical names, Version objects, build tag tuples, and expanded tag sets using packaging.utils","kind":"HOW","packages":["pkg:pypi/packaging@24.2"],"schemaVersion":1,"symbols":["packaging.utils.parse_wheel_filename","packaging.utils.parse_sdist_filename","packaging.utils.canonicalize_name"]},"contractCommand":["python","test/contract.py"],"environment":{"arch":"x64","ecosystem":"pypi","executionContext":"python","language":"python","os":"linux","packageManager":"pip","runtime":"python","schemaVersion":1},"license":"MIT-0","packages":["pkg:pypi/packaging@24.2"],"schemaVersion":1,"symbols":["packaging.utils.parse_wheel_filename","packaging.utils.parse_sdist_filename","packaging.utils.canonicalize_name"],"verifierAdapter":"python@1"}
requirements.txt
packaging==24.2
test/contract.py
from packaging.tags import Tag
from packaging.utils import (
    InvalidSdistFilename,
    InvalidWheelFilename,
    canonicalize_name,
    parse_sdist_filename,
    parse_wheel_filename,
)
from packaging.version import Version


def test_parse_standard_wheel_filename():
    filename = "Distribution_Name-1.0.0-py2.py3-none-any.whl"
    name, version, build, tags = parse_wheel_filename(filename)

    # Name is canonicalized according to PEP 503 (lowercased and underscores to dashes)
    assert name == "distribution-name"
    assert isinstance(name, str)

    # Version is parsed as a Version instance
    assert version == Version("1.0.0")
    assert isinstance(version, Version)

    # Wheel without build tag has an empty tuple build tag
    assert build == ()

    # Compressed tags 'py2.py3' expand into individual Tag objects in a frozenset
    assert isinstance(tags, frozenset)
    assert len(tags) == 2
    assert Tag("py2", "none", "any") in tags
    assert Tag("py3", "none", "any") in tags


def test_parse_wheel_with_build_tag_and_tag_expansion():
    filename = "Distribution_Name-2.1.0-1rc2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
    name, version, build, tags = parse_wheel_filename(filename)

    assert name == "distribution-name"
    assert version == Version("2.1.0")

    # Build tag is parsed into a 2-tuple of (int, str)
    assert build == (1, "rc2")

    # Cartesian product expansion of 1 python tag x 1 abi tag x 2 platform tags = 2 tags
    assert len(tags) == 2
    assert Tag("cp310", "abi3", "manylinux_2_17_x86_64") in tags
    assert Tag("cp310", "abi3", "manylinux2014_x86_64") in tags


def test_invalid_build_tag_rejected():
    # PEP 427 mandates build numbers start with a digit; non-digit build tags raise InvalidWheelFilename
    invalid_filename = "Distribution_Name-1.0.0-beta-py3-none-any.whl"
    try:
        parse_wheel_filename(invalid_filename)
        raise AssertionError("Expected InvalidWheelFilename for non-digit build tag")
    except InvalidWheelFilename:
        pass


def test_invalid_wheel_filenames_rejected():
    # Invalid extension
    try:
        parse_wheel_filename("package-1.0.0-py3-none-any.tar.gz")
        raise AssertionError("Expected InvalidWheelFilename for non-.whl extension")
    except InvalidWheelFilename:
        pass

    # Invalid component count (too few segments)
    try:
        parse_wheel_filename("package-1.0.0-any.whl")
        raise AssertionError("Expected InvalidWheelFilename for too few components")
    except InvalidWheelFilename:
        pass

    # Invalid component count (too many segments)
    try:
        parse_wheel_filename("package-1.0.0-1-2-py3-none-any.whl")
        raise AssertionError("Expected InvalidWheelFilename for too many components")
    except InvalidWheelFilename:
        pass


def test_parse_sdist_filename():
    name, version = parse_sdist_filename("Foo_Bar-1.2.3a4.tar.gz")
    assert name == "foo-bar"
    assert version == Version("1.2.3a4")

    name_zip, version_zip = parse_sdist_filename("Foo_Bar-2.0.0.zip")
    assert name_zip == "foo-bar"
    assert version_zip == Version("2.0.0")

    try:
        parse_sdist_filename("Foo_Bar-1.0.0.whl")
        raise AssertionError("Expected InvalidSdistFilename for .whl extension")
    except InvalidSdistFilename:
        pass

    try:
        parse_sdist_filename("Foo_Bar.tar.gz")
        raise AssertionError("Expected InvalidSdistFilename for missing version")
    except InvalidSdistFilename:
        pass


def test_canonicalize_name():
    assert canonicalize_name("Foo._-BAR") == "foo-bar"
    assert canonicalize_name("foo---bar") == "foo-bar"
    assert canonicalize_name("foo.bar") == "foo-bar"


if __name__ == "__main__":
    test_parse_standard_wheel_filename()
    test_parse_wheel_with_build_tag_and_tag_expansion()
    test_invalid_build_tag_rejected()
    test_invalid_wheel_filenames_rejected()
    test_parse_sdist_filename()
    test_canonicalize_name()
    print("All packaging.utils contract assertions passed.")

オリジンシーダー

csx-seed