From 880b664461b2b697ceb2e52ead788222a8621bca Mon Sep 17 00:00:00 2001 From: Jonathan Yoder Date: Tue, 22 Sep 2026 09:39:22 -0400 Subject: [PATCH 1/2] =?UTF-8?q?Add=20Apache-2.0=20=C2=A74(b)/(c)=20provena?= =?UTF-8?q?nce=20blocks=20and=20fix=20two=20NOTICE=20gaps=20(#19394,=20#19?= =?UTF-8?q?395)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a per-file provenance header (upstream symbols + a Changed: note) to every file carrying ported pypa/packaging, pip, uv, pkginfo, or twine code across version/, distribution/, tags/, wheelname/, extras/, internal/pep508/, requirement/, marker/, and reqtxt/. license/ is excluded: its predecessor (rstudio/package-manager) is Posit's own code, so there is no outside licensor for Apache ยง4(b)/(c) to satisfy there. Corrects NOTICE's uv-pep508/uv-pep440 license claim (they override uv's workspace license to Apache-2.0 OR BSD-2-Clause and are not simply Apache-2.0-OR-MIT) and adds the missing konstin and Aqua Security copyright lines; version/'s NOTICE entry now credits pypa/packaging directly, not just its aquasecurity/rstudio ancestry. Combined with #19395 (citation normalization) because both touch the same package headers: retrofits all 12 pypa/packaging permalink citations in version/ to one pinned SHA (4eb0753, the newest of the three candidates and already used elsewhere in NOTICE) in a symbol-name-first format, via a new exported version.UpstreamPackagingSHA const so version_test.go (an external test package) can cite it too. Comment/header-only change; no behavior touched. Co-Authored-By: Claude Sonnet 5 --- NOTICE | 17 ++++++-- .../internal/distributions/distribution.go | 18 ++++++++ .../internal/distributions/metadata.go | 12 ++++++ distribution/internal/distributions/sdist.go | 10 +++++ distribution/internal/distributions/wheel.go | 11 +++++ .../internal/packages/hash_manager.go | 10 +++++ distribution/parse.go | 10 +++++ distribution/types/types.go | 10 +++++ extras/extras.go | 10 +++++ internal/pep508/grammar_conformance_test.go | 8 ++++ internal/pep508/marker.go | 10 +++++ internal/pep508/requirement.go | 10 +++++ internal/pep508/tokenizer.go | 10 +++++ marker/environment.go | 11 +++++ marker/evaluate.go | 11 +++++ reqtxt/classify.go | 8 ++++ reqtxt/flatten.go | 9 ++++ reqtxt/parse.go | 9 ++++ reqtxt/preprocess.go | 9 ++++ reqtxt/shlex.go | 9 ++++ reqtxt/types.go | 9 ++++ requirement/conformance_test.go | 12 ++++++ requirement/requirement.go | 10 +++++ tags/generate.go | 23 ++++++++++ version/prerelease_spelling_test.go | 5 ++- version/specifier.go | 13 ++++++ version/specifier_conformance_test.go | 9 ++++ version/specifier_test.go | 32 ++++++++++++-- version/specifierset_conformance_test.go | 8 ++++ version/version.go | 42 ++++++++++++++++--- version/version_test.go | 19 ++++++++- wheelname/wheelname.go | 10 +++++ 32 files changed, 389 insertions(+), 15 deletions(-) diff --git a/NOTICE b/NOTICE index 18574fa..6828250 100644 --- a/NOTICE +++ b/NOTICE @@ -6,7 +6,12 @@ license, at your option. See LICENSE-APACHE and LICENSE-MIT. The version/ package is derived from rstudio/go-pep440-version, itself a fork of aquasecurity/go-pep440-version (https://github.com/aquasecurity/go-pep440-version), -licensed under the Apache License, Version 2.0. +Copyright (c) Aqua Security Software Ltd., licensed under the Apache License, +Version 2.0. The version/ package also directly adapts material from +pypa/packaging (https://github.com/pypa/packaging); see the version/-specific +paragraphs below (the letter-normalization tables, cmpkey, the +specifier-matching helpers, and the conformance test ports) for the exact +files, symbols, and pinned commit. The distribution/ package is ported from rstudio/python-distribution-parser (https://github.com/rstudio/python-distribution-parser), Copyright (c) 2024 @@ -94,8 +99,14 @@ The requirement/ package adapts the dependency-specifier grammar of pypa/packaging (https://github.com/pypa/packaging), specifically packaging/_parser.py's `_parse_requirement` and packaging/requirements.py's `Requirement`, licensed under the Apache License, Version 2.0; and Astral -uv's (https://github.com/astral-sh/uv) `uv-pep508` crate, dual-licensed -under the Apache License, Version 2.0, or the MIT license. +uv's (https://github.com/astral-sh/uv) `uv-pep508` crate. Unlike the rest of +uv's workspace, `uv-pep508` (and `uv-pep440`) override the workspace license +per-crate to the Apache License, Version 2.0, or the two-clause BSD license, +and ship their own License-Apache and License-BSD files; `uv-pep508`'s +License-BSD reads Copyright (c) 2023 konstin. `uv-pep508` began as konstin's +independent `pep508_rs` crate, later folded into uv, and pep508_rs's own test +suite already ported cases from pypa/packaging. Material from `uv-pep508` is +taken under whichever of its two arms applies. The marker/ package's Environment platform mapping (os_name, sys_platform, platform_system, platform_release, platform_version) adapts the diff --git a/distribution/internal/distributions/distribution.go b/distribution/internal/distributions/distribution.go index f65d7b9..1c24d3f 100644 --- a/distribution/internal/distributions/distribution.go +++ b/distribution/internal/distributions/distribution.go @@ -1,4 +1,22 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from the Python `pkginfo` package +// (Copyright (c) 2009 Agendaless Consulting, Inc. and Contributors; see +// NOTICE), specifically pkginfo/distribution.py's per-metadata-version +// header attribute tables (HeaderAttrs1_0 through HeaderAttrs2_4) and its +// header-parsing and leading-whitespace-collapsing logic, used under the MIT +// license. +// +// The SafeName function is ported from pypa/twine +// (https://github.com/pypa/twine), Copyright (c) 2013 Donald Stufft and +// individual contributors and Copyright (c) 2015 Ian Cordasco, specifically +// its port of pkg_resources.safe_name (see +// https://github.com/pypa/twine/issues/743), used under the Apache License, +// Version 2.0. See NOTICE for full license and copyright detail for both. +// +// Changed: translated from Python to Go. Parse returns a Go error instead +// of raising; collapseLeadingWS operates on Go strings rather than Python's +// email.message header folding. package distributions diff --git a/distribution/internal/distributions/metadata.go b/distribution/internal/distributions/metadata.go index d8b3e6a..c3e297c 100644 --- a/distribution/internal/distributions/metadata.go +++ b/distribution/internal/distributions/metadata.go @@ -1,4 +1,16 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/twine +// (https://github.com/pypa/twine), Copyright (c) 2013 Donald Stufft and +// individual contributors and Copyright (c) 2015 Ian Cordasco, specifically +// its DIST_EXTENSIONS mapping and distribution-type/Python-version guessing +// logic (DistExtensions and NewDistributionMetadata below), used under the +// Apache License, Version 2.0. See NOTICE for full license and copyright +// detail. +// Changed: translated from Python to Go; returns a Go error instead of +// raising. getFullExtension is a local helper with no twine counterpart, +// needed because Go has no os.path.splitext equivalent for multi-dot +// extensions like ".tar.gz". package distributions diff --git a/distribution/internal/distributions/sdist.go b/distribution/internal/distributions/sdist.go index a077eca..421d9d1 100644 --- a/distribution/internal/distributions/sdist.go +++ b/distribution/internal/distributions/sdist.go @@ -1,4 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/twine +// (https://github.com/pypa/twine), Copyright (c) 2013 Donald Stufft and +// individual contributors and Copyright (c) 2015 Ian Cordasco, specifically +// its SDist class's read() logic that picks the shortest PKG-INFO path +// containing a "Metadata-Version" line, used under the Apache License, +// Version 2.0. See NOTICE for full license and copyright detail. +// Changed: translated from Python to Go; archive reading goes through this +// package's own archiver.ArchiveReader abstraction instead of Python's +// tarfile/zipfile. package distributions diff --git a/distribution/internal/distributions/wheel.go b/distribution/internal/distributions/wheel.go index 2749d2b..da9aedc 100644 --- a/distribution/internal/distributions/wheel.go +++ b/distribution/internal/distributions/wheel.go @@ -1,4 +1,15 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/twine +// (https://github.com/pypa/twine), Copyright (c) 2013 Donald Stufft and +// individual contributors and Copyright (c) 2015 Ian Cordasco, specifically +// its Wheel class: the WHEEL_FILE_RE pattern (wheelFileRe below) and the +// read()/python_version logic that picks the shortest dist-info/METADATA +// path containing a "Metadata-Version" line, used under the Apache License, +// Version 2.0. See NOTICE for full license and copyright detail. +// Changed: translated from Python to Go; archive reading goes through this +// package's own archiver.ArchiveReader abstraction instead of Python's +// zipfile. package distributions diff --git a/distribution/internal/packages/hash_manager.go b/distribution/internal/packages/hash_manager.go index 84dcd64..c0eb8c5 100644 --- a/distribution/internal/packages/hash_manager.go +++ b/distribution/internal/packages/hash_manager.go @@ -1,4 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/twine +// (https://github.com/pypa/twine), Copyright (c) 2013 Donald Stufft and +// individual contributors and Copyright (c) 2015 Ian Cordasco, specifically +// its HashManager class (md5/sha256/blake2 digests computed over chunked +// file reads), used under the Apache License, Version 2.0. See NOTICE for +// full license and copyright detail. +// Changed: translated from Python's hashlib/hashlib.blake2b to Go's +// crypto/md5, crypto/sha256, and golang.org/x/crypto/blake2b; nil-receiver +// guards on md5Hasher/blake2Hasher replace Python's Optional handling. package packages diff --git a/distribution/parse.go b/distribution/parse.go index 20962f1..c000150 100644 --- a/distribution/parse.go +++ b/distribution/parse.go @@ -1,4 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/twine +// (https://github.com/pypa/twine), Copyright (c) 2013 Donald Stufft and +// individual contributors and Copyright (c) 2015 Ian Cordasco, specifically +// its upload command's find_dists and group_wheel_files_first +// (findDistributions and groupWheelFilesFirst below), used under the Apache +// License, Version 2.0. See NOTICE for full license and copyright detail. +// Changed: translated from Python to Go; findDistributions/Parse return Go +// errors instead of raising, and glob expansion goes through filepath.Glob +// instead of Python's glob.glob. package distribution diff --git a/distribution/types/types.go b/distribution/types/types.go index 3ccd3dd..8d1d076 100644 --- a/distribution/types/types.go +++ b/distribution/types/types.go @@ -1,4 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/twine +// (https://github.com/pypa/twine), Copyright (c) 2013 Donald Stufft and +// individual contributors and Copyright (c) 2015 Ian Cordasco, specifically +// the package-file metadata dictionary its upload command builds for a +// multipart request (PackageFile and MetadataMap below), used under the +// Apache License, Version 2.0. See NOTICE for full license and copyright +// detail. +// Changed: translated from Python to Go; PackageFile is a typed struct +// rather than a dict, with json tags standing in for twine's dict keys. package types diff --git a/extras/extras.go b/extras/extras.go index fbc2cc4..43436ed 100644 --- a/extras/extras.go +++ b/extras/extras.go @@ -1,4 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/packaging +// (https://github.com/pypa/packaging), specifically packaging/utils.py's +// canonicalize_name, used under the Apache License, Version 2.0 +// (dual-licensed Apache-2.0 OR BSD-2-Clause; see NOTICE for full license and +// copyright detail). +// Changed: translated from a single re.sub regex into an explicit +// rune-by-rune loop, since extra-name normalization sits on a +// per-dependency hot path; behavior (lowercase, collapse -/_/. runs to one +// "-") is unchanged. package extras diff --git a/internal/pep508/grammar_conformance_test.go b/internal/pep508/grammar_conformance_test.go index 2dacf0a..831c4fd 100644 --- a/internal/pep508/grammar_conformance_test.go +++ b/internal/pep508/grammar_conformance_test.go @@ -1,4 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file port test cases from pypa/packaging +// (https://github.com/pypa/packaging), specifically +// tests/test_requirements.py's class TestRequirementParsing, used under the +// Apache License, Version 2.0 (dual-licensed Apache-2.0 OR BSD-2-Clause; see +// NOTICE for full license and copyright detail). +// Changed: translated from Python/pytest parametrized cases into Go +// table-driven subtests; case selection and pin SHA are noted per-test below. package pep508 diff --git a/internal/pep508/marker.go b/internal/pep508/marker.go index 142c88e..fd68823 100644 --- a/internal/pep508/marker.go +++ b/internal/pep508/marker.go @@ -1,4 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/packaging +// (https://github.com/pypa/packaging), specifically packaging/_parser.py's +// marker productions (_parse_marker and friends) and process_env_var, used +// under the Apache License, Version 2.0 (dual-licensed Apache-2.0 OR +// BSD-2-Clause; see NOTICE for full license and copyright detail). +// Changed: translated the recursive-descent parser from Python's generator- +// based token iteration into Go functions returning (Expr, error); "and"/ +// "or" precedence grouping, built implicitly by upstream's AST shape, is +// rebuilt explicitly here. package pep508 diff --git a/internal/pep508/requirement.go b/internal/pep508/requirement.go index 751d1a7..90309cf 100644 --- a/internal/pep508/requirement.go +++ b/internal/pep508/requirement.go @@ -1,4 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/packaging +// (https://github.com/pypa/packaging), specifically packaging/_parser.py's +// _parse_requirement and packaging/requirements.py's Requirement, used +// under the Apache License, Version 2.0 (dual-licensed Apache-2.0 OR +// BSD-2-Clause; see NOTICE for full license and copyright detail). +// Changed: translated from Python's exception-raising parse functions into +// Go functions returning (RawRequirement, error); name canonicalization, +// extras normalization, and marker evaluation are deferred to the callers +// in package requirement and package marker rather than done inline here. package pep508 diff --git a/internal/pep508/tokenizer.go b/internal/pep508/tokenizer.go index 0a959d6..0725acc 100644 --- a/internal/pep508/tokenizer.go +++ b/internal/pep508/tokenizer.go @@ -1,4 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/packaging +// (https://github.com/pypa/packaging), specifically packaging/_tokenizer.py's +// Tokenizer, Token, ParserSyntaxError, and DEFAULT_RULES, used under the +// Apache License, Version 2.0 (dual-licensed Apache-2.0 OR BSD-2-Clause; see +// NOTICE for full license and copyright detail). +// Changed: translated from Python's re.match-at-position calls into Go's +// regexp.FindStringIndex on a byte-offset substring; DEFAULT_RULES' string +// keys become a typed Kind enum, and ParserSyntaxError becomes *SyntaxError +// returned as a Go error rather than raised. package pep508 diff --git a/marker/environment.go b/marker/environment.go index 6c5db01..cc74ab1 100644 --- a/marker/environment.go +++ b/marker/environment.go @@ -1,4 +1,15 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from Astral's uv +// (https://github.com/astral-sh/uv), specifically the uv-configuration +// crate's TargetTriple (the linux/macos/windows cases of its platform-tag +// logic, adapted to fill os_name, sys_platform, platform_system, +// platform_release, and platform_version), used under the Apache License, +// Version 2.0 (uv workspace dual-licensed Apache-2.0 OR MIT; see NOTICE for +// full license and copyright detail). +// Changed: translated from Rust to Go; returns a Go error +// (ErrUnsupportedTarget) instead of Rust's Result/panic, and reads a +// tags.Target plus InterpreterIdentity instead of TargetTriple's own enum. package marker diff --git a/marker/evaluate.go b/marker/evaluate.go index e8dc46d..7ee59ca 100644 --- a/marker/evaluate.go +++ b/marker/evaluate.go @@ -1,4 +1,15 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/packaging +// (https://github.com/pypa/packaging), specifically packaging/markers.py's +// _eval_op and its operator/specifier dispatch (including +// MARKERS_REQUIRING_VERSION, reflected below as versionTypedVars), used +// under the Apache License, Version 2.0 (dual-licensed Apache-2.0 OR +// BSD-2-Clause; see NOTICE for full license and copyright detail). +// Changed: translated from Python to Go; an unresolvable comparison records +// an Undecidable value instead of raising UndefinedEnvironmentName, and +// version-typed comparisons delegate to package version instead of +// packaging.specifiers. package marker diff --git a/reqtxt/classify.go b/reqtxt/classify.go index 271a7ca..acbed66 100644 --- a/reqtxt/classify.go +++ b/reqtxt/classify.go @@ -1,4 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pip +// (https://github.com/pypa/pip), specifically pip/_internal/utils/misc.py's +// is_url and is_archive_file, and the VCS scheme registration in +// pip/_internal/vcs/{git,mercurial,subversion,bazaar}.py, used under the MIT +// license; see NOTICE for full license and copyright detail. +// Changed: translated from Python to Go as a pure, shape-only string +// classifier that never touches the filesystem, unlike pip's originals. package reqtxt diff --git a/reqtxt/flatten.go b/reqtxt/flatten.go index 5440473..389eb7d 100644 --- a/reqtxt/flatten.go +++ b/reqtxt/flatten.go @@ -1,4 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pip +// (https://github.com/pypa/pip), specifically the include-following of +// pip/_internal/req/req_file.py's RequirementsFileParser._parse_and_recurse, +// used under the MIT license; see NOTICE for full license and copyright +// detail. +// Changed: translated from Python's recursive parser-instance walk into an +// explicit Go recursion building a single flattened File value; the +// nested_constraint propagation rule is reproduced as a plain bool parameter. package reqtxt diff --git a/reqtxt/parse.go b/reqtxt/parse.go index bb834dd..5b1310b 100644 --- a/reqtxt/parse.go +++ b/reqtxt/parse.go @@ -1,4 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pip +// (https://github.com/pypa/pip), specifically pip/_internal/req/req_file.py's +// SUPPORTED_OPTIONS, SUPPORTED_OPTIONS_REQ, break_args_options, and +// process_line, used under the MIT license; see NOTICE for full license and +// copyright detail. +// Changed: translated from Python's optparse-based option handling into +// explicit Go dispatch functions; pip's non-fatal warnings (e.g. --hash with +// no value) are represented as returned errors or dropped values instead. package reqtxt diff --git a/reqtxt/preprocess.go b/reqtxt/preprocess.go index 6b98562..b183eb6 100644 --- a/reqtxt/preprocess.go +++ b/reqtxt/preprocess.go @@ -1,4 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pip +// (https://github.com/pypa/pip), specifically pip/_internal/req/req_file.py's +// COMMENT_RE, ENV_VAR_RE, join_lines, and the preprocess line-joining +// pipeline, used under the MIT license; see NOTICE for full license and +// copyright detail. +// Changed: translated from Python to Go; join_lines' backslash-continuation +// guard is expressed with explicit byte-offset scanning instead of Python's +// regex match objects. package reqtxt diff --git a/reqtxt/shlex.go b/reqtxt/shlex.go index cd459c4..adc1f10 100644 --- a/reqtxt/shlex.go +++ b/reqtxt/shlex.go @@ -1,4 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pip +// (https://github.com/pypa/pip), specifically the POSIX-mode +// shlex.split(line, comments=False, posix=True) behavior pip's +// pip/_internal/req/req_file.py relies on for a requirements-file line, +// used under the MIT license; see NOTICE for full license and copyright +// detail. +// Changed: reimplemented Python's shlex POSIX-mode splitting rules directly +// in Go, since Go has no shlex equivalent in its standard library. package reqtxt diff --git a/reqtxt/types.go b/reqtxt/types.go index 3ab8848..6b4c1a5 100644 --- a/reqtxt/types.go +++ b/reqtxt/types.go @@ -1,4 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pip +// (https://github.com/pypa/pip), specifically the include-following +// bookkeeping (nested_constraint, source file tracking) of +// pip/_internal/req/req_file.py's RequirementsFileParser._parse_and_recurse, +// used under the MIT license; see NOTICE for full license and copyright +// detail. +// Changed: translated from Python's parser-instance state into explicit Go +// struct fields (UnnamedEntry, OptionEntry) carried on each entry value. package reqtxt diff --git a/requirement/conformance_test.go b/requirement/conformance_test.go index 3c5a4c9..7e137f8 100644 --- a/requirement/conformance_test.go +++ b/requirement/conformance_test.go @@ -1,4 +1,16 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/packaging +// (https://github.com/pypa/packaging), specifically +// tests/test_requirements.py's test_basic_valid_requirement_parsing +// cross-product parameters and the invalid-requirement cases of class +// TestRequirementParsing, used under the Apache License, Version 2.0 +// (dual-licensed Apache-2.0 OR BSD-2-Clause; see NOTICE for full license and +// copyright detail). +// Changed: translated from Python/pytest to Go table-driven tests; the +// parametrize cross-product is expressed as a curated subset with +// equivalent coverage. See the divergence notes below for cases where the +// Go expectation intentionally differs from upstream's literal assertion. // This file contains ONLY cases ported from pypa/packaging's test suite, one // Go table per upstream test function. Hand-written cases belong in diff --git a/requirement/requirement.go b/requirement/requirement.go index 3fa6cc4..df916f4 100644 --- a/requirement/requirement.go +++ b/requirement/requirement.go @@ -1,4 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/packaging +// (https://github.com/pypa/packaging), specifically +// packaging/requirements.py's Requirement.__str__ rendering rule (the +// " ; " vs "; " marker separator, chosen so a bare ";" is never ambiguous +// with a ";" inside a URL), used under the Apache License, Version 2.0 +// (dual-licensed Apache-2.0 OR BSD-2-Clause; see NOTICE for full license and +// copyright detail). +// Changed: translated from Python to Go; Parse itself is original glue over +// the already-attributed internal/pep508 parser rather than a further port. package requirement diff --git a/tags/generate.go b/tags/generate.go index 8b6c42f..12c978f 100644 --- a/tags/generate.go +++ b/tags/generate.go @@ -1,4 +1,27 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/packaging +// (https://github.com/pypa/packaging), specifically packaging/tags.py's +// cpython_tags, generic_tags, compatible_tags, sys_tags, _cpython_abis, +// mac_platforms and _mac_binary_formats, and packaging/_manylinux.py's and +// packaging/_musllinux.py's platform_tags (including _manylinux.py's +// _LAST_GLIBC_MINOR placeholder value), used under the Apache License, +// Version 2.0 (dual-licensed Apache-2.0 OR BSD-2-Clause; see NOTICE for full +// license and copyright detail). +// +// The manylinuxFloor table began as Astral uv's (https://github.com/astral-sh/uv) +// uv-platform-tags crate floor table, used under the Apache License, Version +// 2.0 (uv workspace dual-licensed Apache-2.0 OR MIT; see NOTICE). +// +// Changed: translated from Python to Go. Fixed to a declared Target rather +// than the running interpreter/host, so there is no live introspection of +// Py_UNICODE_SIZE, EXT_SUFFIX, or uname -- cpythonExactABI's UCS-4 handling +// and implABI's PyPy suffix are answered from Target fields instead. Returns +// Tag structs and Go errors instead of Python lists/exceptions. manylinuxFloor +// widens uv's riscv64 (2.31) and loongarch64 (2.36) floors to pypa/packaging's +// 2.17 and restores their manylinux2014 legacy alias, which uv's table omits +// (see the comment above manylinuxFloor for why). linuxPlatformTags adds a +// bare "linux_" fallback tag that pypa/packaging does not emit. package tags import ( diff --git a/version/prerelease_spelling_test.go b/version/prerelease_spelling_test.go index cd45613..17b2429 100644 --- a/version/prerelease_spelling_test.go +++ b/version/prerelease_spelling_test.go @@ -67,7 +67,10 @@ func TestParse_LongPreReleaseSpellings(t *testing.T) { // "==1.0preview1" -> "==1.0pre,1" // // pypa/packaging orders its equivalent alternation longest-before-prefix for -// this same reason (Python's re is also leftmost-first): +// this same reason (Python's re is also leftmost-first). Ported from +// pypa/packaging src/packaging/version.py, _VERSION_PATTERN's pre_l +// alternation group. +// Pinned: see UpstreamPackagingSHA (L199 at that commit). // https://github.com/pypa/packaging/blob/4eb0753dba8fcaaac8eb75463374e448f0931558/src/packaging/version.py#L199 func TestNewSpecifiers_LongPreReleaseSpellingIsOneSpecifier(t *testing.T) { tests := []struct { diff --git a/version/specifier.go b/version/specifier.go index 4885ea5..c4fd943 100644 --- a/version/specifier.go +++ b/version/specifier.go @@ -1,4 +1,17 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/packaging +// (https://github.com/pypa/packaging), specifically +// src/packaging/specifiers.py's _version_split, _version_join, +// _is_not_suffix, _numeric_prefix_len, _left_pad, and the bodies of +// Specifier._compare_equal, _compare_compatible, _compare_less_than and +// _compare_greater_than, used under the Apache License, Version 2.0 +// (dual-licensed Apache-2.0 OR BSD-2-Clause; see NOTICE for full license and +// copyright detail). Each ported function below carries its own upstream +// citation and, where behavior diverges, the reason. +// Changed: translated from Python to Go; error returns replace Python's +// exceptions/None-returns, and versionSplit/leftPad operate on string slices +// instead of upstream's list-comprehension-built lists. package version diff --git a/version/specifier_conformance_test.go b/version/specifier_conformance_test.go index 94cddd3..2ca2bd0 100644 --- a/version/specifier_conformance_test.go +++ b/version/specifier_conformance_test.go @@ -1,4 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/packaging +// (https://github.com/pypa/packaging), specifically tests/test_specifiers.py's +// TestSpecifier class, used under the Apache License, Version 2.0 +// (dual-licensed Apache-2.0 OR BSD-2-Clause; see NOTICE for full license and +// copyright detail). +// Changed: translated from Python/pytest to Go table-driven tests; see the +// divergence notes below for cases where the Go expectation intentionally +// differs from upstream's literal assertion. // Conformance tables ported from pypa/packaging's tests/test_specifiers.py, // one Go table per upstream test function. This file contains ONLY cases diff --git a/version/specifier_test.go b/version/specifier_test.go index 2d8c820..6f5ed65 100644 --- a/version/specifier_test.go +++ b/version/specifier_test.go @@ -1,4 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/packaging +// (https://github.com/pypa/packaging), specifically tests/test_specifiers.py's +// module-level SPECIFIERS list and TestSpecifier.test_specifiers_invalid's +// case list, used under the Apache License, Version 2.0 (dual-licensed +// Apache-2.0 OR BSD-2-Clause; see NOTICE for full license and copyright +// detail). +// Changed: translated from Python/pytest to Go table-driven tests; the +// operator-less-specifier case is annotated inline as an intentional R-path +// divergence rather than ported behavior. package version @@ -16,7 +26,9 @@ func TestNewConstraints(t *testing.T) { constraint string wantErr bool }{ - // https://github.com/pypa/packaging/blob/28d2fa0742747cda4bc4530b2a5bc919b7382039/tests/test_specifiers.py#L31-L42 + // Ported from pypa/packaging tests/test_specifiers.py, module-level SPECIFIERS. + // Pinned: see UpstreamPackagingSHA (L33-L43 at that commit). + // https://github.com/pypa/packaging/blob/4eb0753dba8fcaaac8eb75463374e448f0931558/tests/test_specifiers.py#L33-L43 {"~=2.0", false}, {"==2.1.*", false}, {"==2.1.0.3", false}, @@ -29,7 +41,12 @@ func TestNewConstraints(t *testing.T) { {"===lolwat", false}, - // https://github.com/pypa/packaging/blob/28d2fa0742747cda4bc4530b2a5bc919b7382039/tests/test_specifiers.py#L50-L86 + // Ported from pypa/packaging tests/test_specifiers.py, + // TestSpecifier.test_specifiers_invalid's case list. + // Pinned: see UpstreamPackagingSHA (L55-L102 at that commit). Upstream's + // own list has since grown (pre/post/dev-tagged prefix-matching cases, + // non-ASCII local-segment cases) beyond what this file ports. + // https://github.com/pypa/packaging/blob/4eb0753dba8fcaaac8eb75463374e448f0931558/tests/test_specifiers.py#L55-L102 // Operator-less specifier {"2.0", false}, // go-pep-440-version permits this case @@ -95,7 +112,9 @@ func TestNewRSpecifiers(t *testing.T) { constraint string wantErr bool }{ - // https://github.com/pypa/packaging/blob/28d2fa0742747cda4bc4530b2a5bc919b7382039/tests/test_specifiers.py#L31-L42 + // Ported from pypa/packaging tests/test_specifiers.py, module-level SPECIFIERS. + // Pinned: see UpstreamPackagingSHA (L33-L43 at that commit). + // https://github.com/pypa/packaging/blob/4eb0753dba8fcaaac8eb75463374e448f0931558/tests/test_specifiers.py#L33-L43 {"~=2.0", false}, {"==2.1.*", false}, {"==2.1.0.3", false}, @@ -108,7 +127,12 @@ func TestNewRSpecifiers(t *testing.T) { {"===lolwat", false}, - // https://github.com/pypa/packaging/blob/28d2fa0742747cda4bc4530b2a5bc919b7382039/tests/test_specifiers.py#L50-L86 + // Ported from pypa/packaging tests/test_specifiers.py, + // TestSpecifier.test_specifiers_invalid's case list. + // Pinned: see UpstreamPackagingSHA (L55-L102 at that commit). Upstream's + // own list has since grown (pre/post/dev-tagged prefix-matching cases, + // non-ASCII local-segment cases) beyond what this file ports. + // https://github.com/pypa/packaging/blob/4eb0753dba8fcaaac8eb75463374e448f0931558/tests/test_specifiers.py#L55-L102 // Operator-less specifier {"2.0", false}, // go-pep-440-version permits this case diff --git a/version/specifierset_conformance_test.go b/version/specifierset_conformance_test.go index 1c83259..5af23a5 100644 --- a/version/specifierset_conformance_test.go +++ b/version/specifierset_conformance_test.go @@ -1,4 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/packaging +// (https://github.com/pypa/packaging), specifically tests/test_specifiers.py's +// TestSpecifierSet class, used under the Apache License, Version 2.0 +// (dual-licensed Apache-2.0 OR BSD-2-Clause; see NOTICE for full license and +// copyright detail). +// Changed: translated from Python/pytest to Go table-driven tests; upstream +// tests with no Go counterpart are omitted, see the list below. // Conformance tables ported from the TestSpecifierSet class of // pypa/packaging's tests/test_specifiers.py, one Go table per upstream test diff --git a/version/version.go b/version/version.go index f8529b0..2b613c8 100644 --- a/version/version.go +++ b/version/version.go @@ -1,4 +1,17 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/packaging +// (https://github.com/pypa/packaging), specifically +// src/packaging/version.py's letter-normalization table (the pre-release and +// post-release spelling aliases, now merged upstream into a single +// _LETTER_NORMALIZATION dict), _parse_letter_version's implicit-post-release +// branch, and _cmpkey's dev-only pre-release ranking, used under the Apache +// License, Version 2.0 (dual-licensed Apache-2.0 OR BSD-2-Clause; see NOTICE +// for full license and copyright detail). +// Changed: translated from Python to Go. The two alias maps below stay split +// into preReleaseAliases/postReleaseAliases instead of upstream's single +// merged dict, and each also carries identity entries ("a"->"a", "rc"->"rc") +// that upstream omits because its canonical spellings already match. package version @@ -11,11 +24,19 @@ import ( "github.com/rstudio/go-version/pkg/part" ) +// UpstreamPackagingSHA is the single pypa/packaging commit every citation +// comment in this package cites. Update it here first, then re-verify each +// citation's line range and symbol name before repointing the comment URLs. +const UpstreamPackagingSHA = "4eb0753dba8fcaaac8eb75463374e448f0931558" + var ( // The compiled regular expression used to test the validity of a version. versionRegex *regexp.Regexp - // https://github.com/pypa/packaging/blob/a6407e3a7e19bd979e93f58cfc7f6641a7378c46/packaging/version.py#L459-L464 + // Ported from pypa/packaging src/packaging/version.py, module-level + // _LETTER_NORMALIZATION (the pre-release rows: alpha, beta, c, pre, preview). + // Pinned: see UpstreamPackagingSHA (L53-L57 at that commit). + // https://github.com/pypa/packaging/blob/4eb0753dba8fcaaac8eb75463374e448f0931558/src/packaging/version.py#L53-L57 preReleaseAliases = map[string]string{ "a": "a", "alpha": "a", @@ -27,7 +48,10 @@ var ( "preview": "rc", } - // https://github.com/pypa/packaging/blob/a6407e3a7e19bd979e93f58cfc7f6641a7378c46/packaging/version.py#L465-L466 + // Ported from pypa/packaging src/packaging/version.py, module-level + // _LETTER_NORMALIZATION (the post-release rows: rev, r). + // Pinned: see UpstreamPackagingSHA (L58-L59 at that commit). + // https://github.com/pypa/packaging/blob/4eb0753dba8fcaaac8eb75463374e448f0931558/src/packaging/version.py#L58-L59 postReleaseAliases = map[string]string{ "post": "post", "rev": "post", @@ -213,7 +237,10 @@ func Parse(v string) (Version, error) { case "post_l": postL = part.String(postReleaseAliases[strings.ToLower(m)]) case "post_n1", "post_n2": - // https://github.com/pypa/packaging/blob/a6407e3a7e19bd979e93f58cfc7f6641a7378c46/packaging/version.py#L469-L472 + // Ported from pypa/packaging src/packaging/version.py, + // _parse_letter_version's implicit-post-release branch. + // Pinned: see UpstreamPackagingSHA (L1141-L1144 at that commit). + // https://github.com/pypa/packaging/blob/4eb0753dba8fcaaac8eb75463374e448f0931558/src/packaging/version.py#L1141-L1144 if postL == "" { postL = "post" } @@ -259,7 +286,9 @@ func Parse(v string) (Version, error) { }, nil } -// ref. https://github.com/pypa/packaging/blob/a6407e3a7e19bd979e93f58cfc7f6641a7378c46/packaging/version.py#L495 +// Ported from pypa/packaging src/packaging/version.py's _cmpkey. +// Pinned: see UpstreamPackagingSHA (L1178 at that commit). +// https://github.com/pypa/packaging/blob/4eb0753dba8fcaaac8eb75463374e448f0931558/src/packaging/version.py#L1178 func cmpkey(epoch part.BigInt, release []part.BigInt, pre, post, dev letterNumber, local string) key { // Set default values k := key{ @@ -273,7 +302,10 @@ func cmpkey(epoch part.BigInt, release []part.BigInt, pre, post, dev letterNumbe // Remove trailing zeros k.release = part.BigIntSliceToParts(release).Normalize() - // https://github.com/pypa/packaging/blob/a6407e3a7e19bd979e93f58cfc7f6641a7378c46/packaging/version.py#L514-L517 + // Ported from pypa/packaging src/packaging/version.py, _cmpkey's + // dev-only / no-pre-release rank assignment. + // Pinned: see UpstreamPackagingSHA (L1230-L1234 at that commit). + // https://github.com/pypa/packaging/blob/4eb0753dba8fcaaac8eb75463374e448f0931558/src/packaging/version.py#L1230-L1234 if pre.isNull() && post.isNull() && !dev.isNull() { k.pre = part.NegativeInfinity } else if pre.isNull() { diff --git a/version/version_test.go b/version/version_test.go index 75fee08..da463d9 100644 --- a/version/version_test.go +++ b/version/version_test.go @@ -1,4 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/packaging +// (https://github.com/pypa/packaging), specifically tests/test_version.py's +// TestVersion.test_valid_versions and test_invalid_versions (the VERSIONS +// case list and the invalid-version case list), used under the Apache +// License, Version 2.0 (dual-licensed Apache-2.0 OR BSD-2-Clause; see NOTICE +// for full license and copyright detail). +// Changed: translated from Python/pytest to Go table-driven tests. package version_test @@ -72,7 +80,9 @@ var ( } ) -// https://github.com/pypa/packaging/blob/a6407e3a7e19bd979e93f58cfc7f6641a7378c46/tests/test_version.py#L85-L87 +// Ported from pypa/packaging tests/test_version.py, TestVersion.test_valid_versions. +// Pinned: see version.UpstreamPackagingSHA (L175-L177 at that commit). +// https://github.com/pypa/packaging/blob/4eb0753dba8fcaaac8eb75463374e448f0931558/tests/test_version.py#L175-L177 func TestParseValidVersion(t *testing.T) { for _, v := range versions { t.Run(v, func(t *testing.T) { @@ -82,7 +92,12 @@ func TestParseValidVersion(t *testing.T) { } } -// https://github.com/pypa/packaging/blob/a6407e3a7e19bd979e93f58cfc7f6641a7378c46/tests/test_version.py#L102-L104 +// Ported from pypa/packaging tests/test_version.py, TestVersion.test_invalid_versions. +// Pinned: see version.UpstreamPackagingSHA (L215-L217 at that commit). +// Upstream's own list has since grown (spaces, non-ASCII digits, fast-path +// cases) beyond what this file ports; see version_test package doc for the +// curated subset. +// https://github.com/pypa/packaging/blob/4eb0753dba8fcaaac8eb75463374e448f0931558/tests/test_version.py#L215-L217 func TestParseInvalidVersion(t *testing.T) { versions := []string{ // Non sensical versions should be invalid diff --git a/wheelname/wheelname.go b/wheelname/wheelname.go index 4d5beec..994a643 100644 --- a/wheelname/wheelname.go +++ b/wheelname/wheelname.go @@ -1,4 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Portions of this file are ported from pypa/packaging +// (https://github.com/pypa/packaging), specifically packaging/utils.py's +// parse_wheel_filename, used under the Apache License, Version 2.0 +// (dual-licensed Apache-2.0 OR BSD-2-Clause; see NOTICE for full license and +// copyright detail). +// Changed: translated from Python's regex-based filename split into Go's +// strings.Split/CutSuffix; parse_wheel_filename raises InvalidWheelFilename, +// this returns (WheelFilename, error) instead. + package wheelname import ( From b15db551b7d9626071c47c142ab8107c793e86cd Mon Sep 17 00:00:00 2001 From: Jonathan Yoder Date: Tue, 22 Sep 2026 16:35:55 -0400 Subject: [PATCH 2/2] Fix pypa/packaging pin errors in NOTICE and citations (#19394, #19395) 4eb0753 is a main commit 128 commits after the 26.2 release, not the release itself; relabel it everywhere it was called "26.2". Replace 6ce6143, which is the 26.2 tag object rather than a commit, with the commit it points to (84a87ee). Co-Authored-By: Claude Sonnet 5 --- NOTICE | 13 +++++++++---- tags/generate.go | 3 ++- version/adjacent_constraint_test.go | 3 ++- version/specifier_query.go | 2 +- version/version.go | 6 ++++-- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/NOTICE b/NOTICE index 6828250..70c6189 100644 --- a/NOTICE +++ b/NOTICE @@ -44,8 +44,8 @@ tag ordering) from pypa/packaging (https://github.com/pypa/packaging), specifically packaging/tags.py's cpython_tags, generic_tags, compatible_tags, sys_tags, mac_platforms and _mac_binary_formats, packaging/_manylinux.py's platform_tags cross-major glibc walk and its _LAST_GLIBC_MINOR placeholder -value (pinned at 6ce6143ac8eebd91b7b0d38e92618f0702e933af, packaging 26.2), and -packaging/_musllinux.py; and from Astral's uv +value (pinned at commit 84a87ee42483d7352f9502d78a9553da8859aa7a, the release +26.2 tag's commit), and packaging/_musllinux.py; and from Astral's uv (https://github.com/astral-sh/uv), specifically the uv-platform-tags crate, dual-licensed under the Apache License, Version 2.0, or the MIT license. @@ -148,8 +148,13 @@ The version/ package's conformance tests port the PEP 440 version-specifier cases of pypa/packaging (https://github.com/pypa/packaging), Copyright (c) Donald Stufft and individual contributors, specifically tests/test_specifiers.py's classes TestSpecifier and TestSpecifierSet, pinned -at commit 4eb0753dba8fcaaac8eb75463374e448f0931558 (release 26.2), licensed -under the Apache License, Version 2.0. Translated from Python/pytest to Go +at commit 4eb0753dba8fcaaac8eb75463374e448f0931558 (pypa/packaging main, +2026-07-28, 128 commits after the 26.2 release). Both classes gained +unrelated tests and assertions after 26.2; the ported cross-product and +invalid-specifier tables themselves include a non-ASCII case added after +26.2, so 4eb0753 rather than the 26.2 release commit is the pin the ported +content actually matches. Licensed under the Apache License, Version 2.0. +Translated from Python/pytest to Go table-driven tests, in version/specifier_conformance_test.go and version/specifierset_conformance_test.go. Upstream tests resting on implementation details with no counterpart here are not ported, and the reason diff --git a/tags/generate.go b/tags/generate.go index 12c978f..56da71a 100644 --- a/tags/generate.go +++ b/tags/generate.go @@ -430,7 +430,8 @@ func linuxPlatformTags(t Target) []string { // // Copying the placeholder rather than inventing our own means we inherit // upstream's correction when glibc 3 actually ships. Upstream pinned at -// 6ce6143ac8eebd91b7b0d38e92618f0702e933af (packaging 26.2). +// commit 84a87ee42483d7352f9502d78a9553da8859aa7a (the release 26.2 tag's +// commit). const lastGlibcMinor = 50 // glibcVersion is a (major, minor) glibc version used while building the diff --git a/version/adjacent_constraint_test.go b/version/adjacent_constraint_test.go index 7adcdb2..7864c8f 100644 --- a/version/adjacent_constraint_test.go +++ b/version/adjacent_constraint_test.go @@ -88,7 +88,8 @@ func TestCommaRequirementDoesNotNarrowValidForms(t *testing.T) { {">= 1.0,", "trailing comma, which upstream also accepts"}, // Upstream drops every blank comma-split item, not just a trailing one: // `[s.strip() for s in specifiers.split(",") if s.strip()]` in - // SpecifierSet.__init__ (pypa/packaging @ 4eb0753, release 26.2). + // SpecifierSet.__init__ (pypa/packaging @ 4eb0753, unchanged since the + // 26.2 release). // Verified: SpecifierSet(",>=1") and SpecifierSet(">=1,,<2") both parse, // to lengths 1 and 2. {",>= 1.0", "leading comma, which upstream also accepts"}, diff --git a/version/specifier_query.go b/version/specifier_query.go index 188d80b..57d40f3 100644 --- a/version/specifier_query.go +++ b/version/specifier_query.go @@ -7,7 +7,7 @@ // `bool(list(self.filter([item])))` so the two can never disagree. // // Upstream pinned at 4eb0753dba8fcaaac8eb75463374e448f0931558 -// (pypa/packaging 26.2). +// (pypa/packaging main, 128 commits after the 26.2 release). package version diff --git a/version/version.go b/version/version.go index 2b613c8..617590d 100644 --- a/version/version.go +++ b/version/version.go @@ -25,8 +25,10 @@ import ( ) // UpstreamPackagingSHA is the single pypa/packaging commit every citation -// comment in this package cites. Update it here first, then re-verify each -// citation's line range and symbol name before repointing the comment URLs. +// comment in this package cites: pypa/packaging main, 128 commits after the +// 26.2 release, not the 26.2 release commit itself. Update it here first, +// then re-verify each citation's line range and symbol name before +// repointing the comment URLs. const UpstreamPackagingSHA = "4eb0753dba8fcaaac8eb75463374e448f0931558" var (