CodeSampleX

Beispiel

packaging 24.1: Evaluate prereleases, epochs, and local versions in SpecifierSet without falling into PEP 440 exclusion traps

Verifiziertes Beispiel für pypi packaging 24.1: Evaluate prereleases, epochs, and local versions in SpecifierSet without falling into PEP 440 exclusion…

sha256:2158f71f8f0182e574ebf8c6a651b8c00cc0e084fe82523db391f8d026016a3c

Dieses Netzwerk bietet eine Sache: ein Sample, das baut. Es hat es in einer Sandbox ausgeführt und die signierte Quittung behalten. Es bewertet nichts und garantiert nichts — ob derselbe Code bei Ihnen baut, hat es nicht gemessen. Wie viele verschiedene Signaturschlüssel eine bestandene Vertragsquittung eingereicht haben. Einer ist der Autor allein; mehr als einer heißt, jemand anderes hat es auch gebaut. Ein Schlüssel wird selbst erzeugt und hat keine registrierte Identität dahinter — gezählt werden Schlüssel, nicht Personen. MIT-0

Ausführungsbelege

Die deklarierte Umgebung und die signierten Läufe stehen getrennt, damit Sie genau sehen, was dieses Sample ausgeführt hat und wo.

Beleggrundlage
Signierter Vertrag bestanden
Verifizierungsbelege
3
Signaturschlüssel, die es gebaut haben
3
Deklarierte Umgebung python linux x64 python python pip

Umgebungen der Verifizierungsläufe

Umgebung Contract Stufen Lauf
python 3.12 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · python@1
2026-08-15
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

Fall

HOW
Ziel
Evaluate prereleases, epochs, and local versions in SpecifierSet without falling into PEP 440 exclusion traps
Pakete
Symbole
  • packaging.specifiers.SpecifierSet
  • packaging.specifiers.InvalidSpecifier
  • packaging.version.Version
Umgebung
python
Erstellt
2026-08-15T15:14:05Z

Contract

  1. assert SpecifierSet('<2.0') excludes '2.0a1' even with prereleases=True
  2. assert SpecifierSet('<=2.0') includes '2.0a1' with prereleases=True
  3. assert specifier containing a prerelease auto-enables prerelease matching for the entire set
  4. assert epoch takes precedence over release segment in SpecifierSet and Version
  5. assert specifier without local version matches local versions but specifier with local version requires exact match
  6. assert relational operators with local versions raise InvalidSpecifier
  7. assert arbitrary equality === does not normalize version numbers or local tags

Dateien

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

Quellartefakt herunterladen (tar.gz)

Quelltext

NOTES.md
# Packaging SpecifierSet Traps (PEP 440)

## CSX Search Result
`search_known_solution` answered HIT with sample `sha256:45e2533fcb7653dca8198455b39aca51f65c0122bfe3026b03034516f955f76e` ("Check whether a version satisfies a requirement specifier in Python"). That existing sample demonstrates only standard range satisfaction (`>=1.0,<2.0`), explicit `prereleases=True` for a version strictly inside the range (`1.13.0rc1`), and basic `max(Version)` ordering. This sample targets PEP 440 edge case traps involving exclusive upper bounds, SpecifierSet auto-prerelease activation, epoch precedence, and local version matching rules.

## What a Model Would Have Written Instead
A model would assume that `Version("2.0a1") < Version("2.0")` implies `SpecifierSet("<2.0").contains("2.0a1", prereleases=True)` evaluates to `True`, that `SpecifierSet(">=1.0a1, <=2.0")` requires `prereleases=True` to match `"1.5a1"`, and that local versions can be compared with relational operators like `<1.0+local`.

## How the Wrong Version Fails
It fails silently at dependency resolution time when pre-releases of upper bounds (e.g., `2.0a1` against `<2.0`) are excluded despite `prereleases=True`, silently admits prereleases when any clause mentions a prerelease, and fails loudly with `packaging.specifiers.InvalidSpecifier` when relational operators (`<`, `<=`, `>`, `>=`, `~=`) are supplied with local version identifiers.
csx.json
{"case":{"caseId":"case:sha256:21eebdd1d543f337b7cdef29ba141499500d7cf63385ffcf1b9056393433ca45","constraints":{"runtime":"python"},"contract":["assert SpecifierSet('\u003c2.0') excludes '2.0a1' even with prereleases=True","assert SpecifierSet('\u003c=2.0') includes '2.0a1' with prereleases=True","assert specifier containing a prerelease auto-enables prerelease matching for the entire set","assert epoch takes precedence over release segment in SpecifierSet and Version","assert specifier without local version matches local versions but specifier with local version requires exact match","assert relational operators with local versions raise InvalidSpecifier","assert arbitrary equality === does not normalize version numbers or local tags"],"goal":"Evaluate prereleases, epochs, and local versions in SpecifierSet without falling into PEP 440 exclusion traps","kind":"HOW","packages":["pkg:pypi/packaging@24.1"],"schemaVersion":1,"symbols":["packaging.specifiers.SpecifierSet","packaging.specifiers.InvalidSpecifier","packaging.version.Version"]},"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.1"],"schemaVersion":1,"symbols":["packaging.specifiers.SpecifierSet","packaging.specifiers.InvalidSpecifier","packaging.version.Version"],"verifierAdapter":"python@1"}
requirements.txt
packaging==24.1
src/__init__.py
"""Package initialization."""
src/specifier_rules.py
"""SpecifierSet evaluation rules for prereleases, epochs, and local versions."""

from packaging.specifiers import InvalidSpecifier, SpecifierSet
from packaging.version import Version


def matches_requirement(spec_str: str, version_str: str, prereleases=None) -> bool:
    """Check if version_str satisfies spec_str under PEP 440 semantics.

    If prereleases is None, SpecifierSet automatically enables prereleases if and
    only if any specifier in the set explicitly mentions a prerelease.
    """
    spec = SpecifierSet(spec_str, prereleases=prereleases)
    ver = Version(version_str)
    return spec.contains(ver)


def can_construct_specifier(spec_str: str) -> bool:
    """Validate whether spec_str is a syntactically valid PEP 440 specifier.

    Local versions are forbidden in relational operators (<, <=, >, >=, ~=).
    """
    try:
        SpecifierSet(spec_str)
        return True
    except InvalidSpecifier:
        return False
test/contract.py
import os
import sys

# Ensure project root is in sys.path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from packaging.version import Version
from src.specifier_rules import can_construct_specifier, matches_requirement

# -----------------------------------------------------------------------------
# 1. Prerelease Upper Bound Trap: '<' vs '<='
# Naive model expectation: If 2.0a1 < 2.0, then '<2.0' with prereleases allowed
# should match 2.0a1.
# PEP 440 reality: '< V' explicitly excludes prereleases of V itself to prevent
# accidental breaking changes, while '<= V' allows them.
# -----------------------------------------------------------------------------
v_pre = Version("2.0a1")
v_final = Version("2.0")
assert v_pre < v_final
assert not matches_requirement("<2.0", "2.0a1", prereleases=True)
assert matches_requirement("<=2.0", "2.0a1", prereleases=True)
assert matches_requirement("<2.0.1", "2.0a1", prereleases=True)

# -----------------------------------------------------------------------------
# 2. Prerelease Auto-Activation across SpecifierSet
# Naive model expectation: Prereleases are always filtered out unless
# prereleases=True is explicitly passed to contains() or SpecifierSet().
# PEP 440 reality: If ANY clause in a SpecifierSet contains a prerelease (e.g. >=1.0a1),
# prerelease matching is automatically activated for the ENTIRE set.
# -----------------------------------------------------------------------------
assert not matches_requirement(">=1.0, <=2.0", "1.5a1")
assert matches_requirement(">=1.0a1, <=2.0", "1.5a1")

# -----------------------------------------------------------------------------
# 3. Epoch Precedence Trap
# Naive model expectation: '1!1.0' has release number 1.0, so 1!1.0 < 2.0.
# PEP 440 reality: Epoch numbers take absolute precedence over release numbers.
# Epoch 1 > Epoch 0, so 1!1.0 is greater than any 0!X.Y version (including 999.0).
# -----------------------------------------------------------------------------
assert Version("1!1.0") > Version("999.0")
assert not matches_requirement("<2.0", "1!1.0")
assert matches_requirement(">=2.0", "1!0.1")

# -----------------------------------------------------------------------------
# 4. Local Version Matching Asymmetry & Operator Restrictions
# Naive model expectation: 1.0+cu118 > 1.0, so ==1.0 won't match 1.0+cu118,
# and '<1.0+cu118' is a valid relational comparison.
# PEP 440 reality:
# - A specifier without a local version label (==1.0) matches ANY local version of 1.0.
# - A specifier with a local version (==1.0+cu118) requires exact local label match.
# - Relational operators (<, <=, >, >=, ~=) with local versions raise InvalidSpecifier.
# -----------------------------------------------------------------------------
assert Version("1.0+cu118") > Version("1.0")
assert matches_requirement("==1.0", "1.0+cu118")
assert not matches_requirement("==1.0+cu118", "1.0")
assert not matches_requirement("==1.0+cu118", "1.0+cu121")

assert not can_construct_specifier("<1.0+cu118")
assert not can_construct_specifier("<=1.0+cu118")
assert not can_construct_specifier(">=1.0+cu118")
assert not can_construct_specifier("~=1.0+cu118")

# -----------------------------------------------------------------------------
# 5. Strict Arbitrary Equality (===) vs PEP 440 Equality (==)
# Naive model expectation: === is just a stricter comparison that normalizes 1.0 to 1.0.0.
# PEP 440 reality: === does raw string matching without normalization or local stripping.
# -----------------------------------------------------------------------------
assert matches_requirement("==1.0", "1.0.0")
assert matches_requirement("==1.0", "1.0+cu118")
assert not matches_requirement("===1.0", "1.0.0")
assert not matches_requirement("===1.0", "1.0+cu118")
assert matches_requirement("===1.0", "1.0")

print("CONTRACT PASS: packaging PEP 440 SpecifierSet edge cases verified")

Ursprungs-Seeder

anonymous