fix: local version identifiers in python requirements parsing (#4959)

Signed-off-by: Keith Zantow <kzantow@gmail.com>
This commit is contained in:
Keith Zantow 2026-06-08 11:12:47 -04:00 committed by GitHub
parent 908eb57890
commit 63232bf725
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 42 additions and 2 deletions

View File

@ -29,8 +29,8 @@ const (
// namePattern matches: requests[security] // namePattern matches: requests[security]
namePattern = `(?P<name>\w[\w\[\],\s-_\.]+)` namePattern = `(?P<name>\w[\w\[\],\s-_\.]+)`
// versionConstraintPattern matches: == 2.8.* // versionConstraintPattern matches: == 2.8.* (including local version identifiers, e.g. == 1.2.3+gcr.2)
versionConstraintPattern = `(?P<versionConstraint>([^\S\r\n]*[~=>!<]+\s*[0-9a-zA-Z.*]+[^\S\r\n]*,?)+)?(@[^\S\r\n]*(?P<url>[^;]*))?` versionConstraintPattern = `(?P<versionConstraint>([^\S\r\n]*[~=>!<]+\s*[0-9a-zA-Z.*+]+[^\S\r\n]*,?)+)?(@[^\S\r\n]*(?P<url>[^;]*))?`
// markersPattern matches: python_version < "2.7" and sys_platform == "linux" // markersPattern matches: python_version < "2.7" and sys_platform == "linux"
markersPattern = `(;(?P<markers>.*))?` markersPattern = `(;(?P<markers>.*))?`

View File

@ -140,6 +140,18 @@ func TestParseRequirementsTxt(t *testing.T) {
VersionConstraint: "== 1.0.0", VersionConstraint: "== 1.0.0",
}, },
}, },
{
Name: "local-version",
Version: "1.2.3+gcr.2",
PURL: "pkg:pypi/local-version@1.2.3%2Bgcr.2",
Locations: locations,
Language: pkg.Python,
Type: pkg.PythonPkg,
Metadata: pkg.PythonRequirementsEntry{
Name: "local-version",
VersionConstraint: "== 1.2.3+gcr.2",
},
},
} }
var testCases = []struct { var testCases = []struct {
@ -357,6 +369,23 @@ func Test_newRequirement(t *testing.T) {
Markers: "sys_platform == 'win32'", Markers: "sys_platform == 'win32'",
}, },
}, },
{
name: "local version identifier",
raw: "local-version == 1.2.3+gcr.2",
want: &unprocessedRequirement{
Name: "local-version",
VersionConstraint: "== 1.2.3+gcr.2",
},
},
{
name: "local version identifier with markers",
raw: "local-version == 1.2.3+ubuntu1 ; sys_platform == 'linux'",
want: &unprocessedRequirement{
Name: "local-version",
VersionConstraint: "== 1.2.3+ubuntu1",
Markers: "sys_platform == 'linux'",
},
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
@ -388,6 +417,16 @@ func Test_parseVersion(t *testing.T) {
version: " === 1.26.20 ", version: " === 1.26.20 ",
want: "1.26.20", want: "1.26.20",
}, },
{
name: "local version identifier",
version: " == 1.2.3+gcr.2 ",
want: "1.2.3+gcr.2",
},
{
name: "arbitrary equality with local version identifier",
version: " === 1.2.3+ubuntu1 ",
want: "1.2.3+ubuntu1",
},
{ {
name: "resolve lowest, simple constraint", name: "resolve lowest, simple constraint",
version: " >= 1.0.0 ", version: " >= 1.0.0 ",

View File

@ -25,3 +25,4 @@ celery[redis, pytest] == 4.4.7 # should remove [redis, pytest]
requests[security] == 2.8.* ; python_version < "2.7" and sys_platform == "linux" requests[security] == 2.8.* ; python_version < "2.7" and sys_platform == "linux"
GithubSampleProject == 3.7.1 @ git+https://github.com/owner/repo@releases/tag/v3.7.1 GithubSampleProject == 3.7.1 @ git+https://github.com/owner/repo@releases/tag/v3.7.1
FrIeNdLy-_-bArD == 1.0.0 FrIeNdLy-_-bArD == 1.0.0
local-version == 1.2.3+gcr.2