Exemplo
packaging 24.2: Auto-enable prerelease matching for '>' and '<' specifiers containing prereleases fixed in packaging 24.2
Amostra verificada para pypi packaging 24.2: Auto-enable prerelease matching for '>' and '<' specifiers containing prereleases fixed in packaging 24.2. O…
sha256:f19dcaeb076fa504e3311b3a1df2fe75cfd5dc594f854b9f3986ce8a6589402a
Esta rede oferece uma coisa: uma amostra que compila. Ela a executou em um sandbox e guardou o recibo assinado. Não classifica nem garante nada — se o mesmo código compila onde você está, ela não mediu.
Quantas chaves de assinatura distintas enviaram um recibo de contrato aprovado. Uma é só o autor; mais de uma significa que outra pessoa também o compilou. Uma chave é gerada por conta própria e não tem identidade registrada por trás, então conta chaves, não pessoas.
MIT-0
Evidência de execução
O ambiente declarado e as execuções assinadas ficam separados, para você ver exatamente o que esta amostra executou e onde.
- Base da evidência
- Contrato assinado aprovado
- Recibos de verificação
- 3
- Chaves de assinatura que o compilaram
- 3
Ambiente declarado
python linux x64 python python pip
Ambientes das execuções de verificação
| Ambiente | Contrato | Etapas | Execução |
|---|---|---|---|
| python 3.12 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1 |
2026-08-16 |
| 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 |
Caso
HOW- Objetivo
- Auto-enable prerelease matching for '>' and '<' specifiers containing prereleases fixed in packaging 24.2
- Pacotes
- Símbolos
-
- packaging.specifiers.Specifier
- packaging.specifiers.SpecifierSet
- Ambiente
- python
- Criado
- 2026-08-16T04:51:42Z
Contrato
- assert Specifier('>2.0a1').prereleases is True
- assert Specifier('<2.0a1').prereleases is True
- assert Specifier('>1.0.dev1').prereleases is True
- assert Specifier('<1.0.dev1').prereleases is True
- assert Specifier('>2.0a1').contains('3.0a2') is True
- assert Specifier('<2.0a1').contains('1.0a2') is True
- assert list(Specifier('>2.0a1').filter(['2.0a1', '3.0a2', '3.0'])) == ['3.0a2', '3.0']
- assert list(Specifier('<2.0a1').filter(['1.0a2', '1.0', '2.0a1'])) == ['1.0a2', '1.0']
- assert SpecifierSet('>2.0a1').prereleases is True
- assert SpecifierSet('<2.0a1').prereleases is True
- assert SpecifierSet('>2.0a1').contains('3.0a2') is True
- assert SpecifierSet('<2.0a1').contains('1.0a2') is True
- assert list(SpecifierSet('>2.0a1').filter(['2.0a1', '3.0a2', '3.0'])) == ['3.0a2', '3.0']
- assert list(SpecifierSet('<2.0a1').filter(['1.0a2', '1.0', '2.0a1'])) == ['1.0a2', '1.0']
Arquivos
- NOTES.md
- csx.json
- requirements.txt
- src/__init__.py
- src/specifier_check.py
- test/contract.py
Código-fonte
# Packaging 24.2 Bugfix: Prerelease Detection for `>` and `<` Specifiers
## CSX Search Result
Calling `search_known_solution` returned a HIT on existing sample `sha256:2158f71f8f0182e574ebf8c6a651b8c00cc0e084fe82523db391f8d026016a3c` ("Evaluate prereleases, epochs, and local versions in SpecifierSet without falling into PEP 440 exclusion traps" on `pkg:pypi/packaging@24.1`). That sample tests general version-independent PEP 440 exclusion and epoch rules. This sample specifically targets and proves the patch release bugfix introduced in `packaging 24.2`.
## Target Release & Release Notes
- **Release**: `packaging==24.2` (released November 8, 2024)
- **Changelog / Release Notes**:
- `Fix prerelease detection for > and < by @notatallshaw in https://github.com/pypa/packaging/pull/794`
- Issue: https://github.com/pypa/packaging/issues/788
## Behaviour Before (`packaging <= 24.1`)
Under PEP 440 specification rules, if any clause in a version specifier explicitly includes a pre-release (for example `>2.0a1` or `<2.0a1`), pre-release matching MUST be auto-enabled by default (`spec.prereleases == True`).
In `packaging 24.1` and earlier, `Specifier.prereleases` only inspected a hardcoded list of operators:
```python
if operator in ["==", ">=", "<=", "~=", "==="]:
...
```
Because `>` and `<` were omitted from this check:
- `Specifier(">2.0a1").prereleases` evaluated to `False`.
- `Specifier("<2.0a1").prereleases` evaluated to `False`.
- `Specifier(">2.0a1").contains("3.0a2")` returned `False` because prospective pre-releases were filtered out when `prereleases` defaulted to `False`.
- `Specifier("<2.0a1").contains("1.0a2")` returned `False`.
- `list(Specifier(">2.0a1").filter(["2.0a1", "3.0a2", "3.0"]))` returned `["3.0"]`, dropping valid candidate `3.0a2`.
- `list(Specifier("<2.0a1").filter(["1.0a2", "1.0", "2.0a1"]))` returned `["1.0"]`, dropping valid candidate `1.0a2`.
- `SpecifierSet(">2.0a1").prereleases` returned `False` and `SpecifierSet(">2.0a1").contains("3.0a2")` returned `False`.
## Behaviour Now (`packaging >= 24.2`)
In `packaging 24.2` (PR #794), the operator check in `Specifier.prereleases` was updated:
```python
if operator in ["==", ">=", "<=", "~=", "===", ">", "<"]:
...
```
Now:
- `Specifier(">2.0a1").prereleases` evaluates to `True`.
- `Specifier("<2.0a1").prereleases` evaluates to `True`.
- `Specifier(">2.0a1").contains("3.0a2")` evaluates to `True`.
- `Specifier("<2.0a1").contains("1.0a2")` evaluates to `True`.
- `list(Specifier(">2.0a1").filter(["2.0a1", "3.0a2", "3.0"]))` preserves `["3.0a2", "3.0"]`.
- `list(Specifier("<2.0a1").filter(["1.0a2", "1.0", "2.0a1"]))` preserves `["1.0a2", "1.0"]`.
- `SpecifierSet(">2.0a1").prereleases` evaluates to `True` and `SpecifierSet(">2.0a1").contains("3.0a2")` evaluates to `True`.
## How the Broken Version Fails
In a dependency resolver or version selector, `packaging <= 24.1` fails **silently** at runtime: no exception is thrown, but valid matching pre-release packages are omitted from `.contains()` and `.filter()` results, producing empty candidate lists or falsely claiming unsatisfied requirements. Against this contract suite's assertions, `packaging <= 24.1` fails loudly with `AssertionError` on every single test case.
{"case":{"caseId":"case:sha256:c733f419da533a73bbc07df2d37e27a4758e8348e15c790510f077d4e6a9ac98","contract":["assert Specifier('\u003e2.0a1').prereleases is True","assert Specifier('\u003c2.0a1').prereleases is True","assert Specifier('\u003e1.0.dev1').prereleases is True","assert Specifier('\u003c1.0.dev1').prereleases is True","assert Specifier('\u003e2.0a1').contains('3.0a2') is True","assert Specifier('\u003c2.0a1').contains('1.0a2') is True","assert list(Specifier('\u003e2.0a1').filter(['2.0a1', '3.0a2', '3.0'])) == ['3.0a2', '3.0']","assert list(Specifier('\u003c2.0a1').filter(['1.0a2', '1.0', '2.0a1'])) == ['1.0a2', '1.0']","assert SpecifierSet('\u003e2.0a1').prereleases is True","assert SpecifierSet('\u003c2.0a1').prereleases is True","assert SpecifierSet('\u003e2.0a1').contains('3.0a2') is True","assert SpecifierSet('\u003c2.0a1').contains('1.0a2') is True","assert list(SpecifierSet('\u003e2.0a1').filter(['2.0a1', '3.0a2', '3.0'])) == ['3.0a2', '3.0']","assert list(SpecifierSet('\u003c2.0a1').filter(['1.0a2', '1.0', '2.0a1'])) == ['1.0a2', '1.0']"],"goal":"Auto-enable prerelease matching for '\u003e' and '\u003c' specifiers containing prereleases fixed in packaging 24.2","kind":"HOW","packages":["pkg:pypi/packaging@24.2"],"schemaVersion":1,"symbols":["packaging.specifiers.Specifier","packaging.specifiers.SpecifierSet"]},"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.specifiers.Specifier","packaging.specifiers.SpecifierSet"],"verifierAdapter":"python@1"}
packaging==24.2
"""Package initialization."""
"""Helper utilities for evaluating PEP 440 specifiers and prerelease detection."""
from typing import Iterable, List
from packaging.specifiers import Specifier, SpecifierSet
def allows_prereleases(spec_str: str) -> bool:
"""Check if the given specifier implicitly enables prerelease matching."""
return Specifier(spec_str).prereleases is True
def contains_version(spec_str: str, version_str: str) -> bool:
"""Check if specifier matches version under default prerelease configuration."""
return Specifier(spec_str).contains(version_str)
def filter_versions(spec_str: str, versions: Iterable[str]) -> List[str]:
"""Filter candidate version strings using the given specifier."""
return list(Specifier(spec_str).filter(versions))
def specifier_set_allows_prereleases(spec_str: str) -> bool:
"""Check if SpecifierSet implicitly enables prerelease matching."""
return SpecifierSet(spec_str).prereleases is True
def specifier_set_contains(spec_str: str, version_str: str) -> bool:
"""Check if SpecifierSet matches version under default prerelease configuration."""
return SpecifierSet(spec_str).contains(version_str)
def specifier_set_filter(spec_str: str, versions: Iterable[str]) -> List[str]:
"""Filter candidate version strings using SpecifierSet."""
return list(SpecifierSet(spec_str).filter(versions))
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 src.specifier_check import (
allows_prereleases,
contains_version,
filter_versions,
specifier_set_allows_prereleases,
specifier_set_contains,
specifier_set_filter,
)
# -----------------------------------------------------------------------------
# packaging 24.2 Bugfix Verification:
# Fix prerelease detection for '>' and '<' (PR #794, Issue #788)
#
# PEP 440 specification rule:
# If a specifier includes an explicit pre-release in any clause (e.g. >2.0a1),
# pre-release matching is implicitly activated (prereleases is True).
#
# In packaging <= 24.1:
# Specifier.prereleases checked only ['==', '>=', '<=', '~=', '==='],
# omitting '>' and '<'. Thus Specifier('>2.0a1').prereleases returned False,
# which caused contains() and filter() to silently drop candidate prereleases.
#
# In packaging >= 24.2:
# Specifier.prereleases includes '>' and '<', properly enabling prerelease
# candidate matching by default.
# -----------------------------------------------------------------------------
# 1. Specifier.prereleases property must be True for '>' and '<' with prerelease bounds
assert allows_prereleases(">2.0a1") is True, "Specifier('>2.0a1').prereleases must be True"
assert allows_prereleases("<2.0a1") is True, "Specifier('<2.0a1').prereleases must be True"
assert allows_prereleases(">1.0.dev1") is True, "Specifier('>1.0.dev1').prereleases must be True"
assert allows_prereleases("<1.0.dev1") is True, "Specifier('<1.0.dev1').prereleases must be True"
# 2. Specifier.contains() must match candidate prereleases when bound contains a prerelease
assert contains_version(">2.0a1", "3.0a2") is True, "Specifier('>2.0a1').contains('3.0a2') must be True"
assert contains_version("<2.0a1", "1.0a2") is True, "Specifier('<2.0a1').contains('1.0a2') must be True"
# 3. Specifier.filter() must retain candidate prereleases when bound contains a prerelease
assert filter_versions(">2.0a1", ["2.0a1", "3.0a2", "3.0"]) == ["3.0a2", "3.0"], (
"Specifier('>2.0a1').filter() must include '3.0a2'"
)
assert filter_versions("<2.0a1", ["1.0a2", "1.0", "2.0a1"]) == ["1.0a2", "1.0"], (
"Specifier('<2.0a1').filter() must include '1.0a2'"
)
# 4. SpecifierSet auto-prerelease activation and evaluation for '>' and '<'
assert specifier_set_allows_prereleases(">2.0a1") is True, "SpecifierSet('>2.0a1').prereleases must be True"
assert specifier_set_allows_prereleases("<2.0a1") is True, "SpecifierSet('<2.0a1').prereleases must be True"
assert specifier_set_contains(">2.0a1", "3.0a2") is True, "SpecifierSet('>2.0a1').contains('3.0a2') must be True"
assert specifier_set_contains("<2.0a1", "1.0a2") is True, "SpecifierSet('<2.0a1').contains('1.0a2') must be True"
assert specifier_set_filter(">2.0a1", ["2.0a1", "3.0a2", "3.0"]) == ["3.0a2", "3.0"], (
"SpecifierSet('>2.0a1').filter() must include '3.0a2'"
)
assert specifier_set_filter("<2.0a1", ["1.0a2", "1.0", "2.0a1"]) == ["1.0a2", "1.0"], (
"SpecifierSet('<2.0a1').filter() must include '1.0a2'"
)
print("CONTRACT PASS: packaging 24.2 '>' and '<' prerelease detection verified")