Skip to content

Commit ed0d372

Browse files
committed
Adding platform_release constraints
1 parent 32bd232 commit ed0d372

3 files changed

Lines changed: 85 additions & 21 deletions

File tree

src/poetry/core/constraints/version/parser.py

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,21 +77,21 @@ def parse_single_constraint(
7777
constraint: str, *, is_marker_constraint: bool = False
7878
) -> VersionConstraint:
7979
from poetry.core.constraints.version.patterns import BASIC_CONSTRAINT
80+
from poetry.core.constraints.version.patterns import BASIC_RELEASE_CONSTRAINT
8081
from poetry.core.constraints.version.patterns import CARET_CONSTRAINT
8182
from poetry.core.constraints.version.patterns import TILDE_CONSTRAINT
8283
from poetry.core.constraints.version.patterns import TILDE_PEP440_CONSTRAINT
8384
from poetry.core.constraints.version.patterns import X_CONSTRAINT
8485
from poetry.core.constraints.version.version import Version
8586
from poetry.core.constraints.version.version_range import VersionRange
8687
from poetry.core.constraints.version.version_union import VersionUnion
88+
from poetry.core.version.pep440 import ReleaseTag
8789

88-
m = re.match(r"(?i)^v?[xX*](\.[xX*])*$", constraint)
89-
if m:
90+
if m := re.match(r"(?i)^v?[xX*](\.[xX*])*$", constraint):
9091
return VersionRange()
9192

9293
# Tilde range
93-
m = TILDE_CONSTRAINT.match(constraint)
94-
if m:
94+
if m := TILDE_CONSTRAINT.match(constraint):
9595
try:
9696
version = Version.parse(m.group("version"))
9797
except InvalidVersion as e:
@@ -106,8 +106,8 @@ def parse_single_constraint(
106106
return VersionRange(version, high, include_min=True)
107107

108108
# PEP 440 Tilde range (~=)
109-
m = TILDE_PEP440_CONSTRAINT.match(constraint)
110-
if m:
109+
110+
if m := TILDE_PEP440_CONSTRAINT.match(constraint):
111111
try:
112112
version = Version.parse(m.group("version"))
113113
except InvalidVersion as e:
@@ -123,8 +123,8 @@ def parse_single_constraint(
123123
return VersionRange(version, high, include_min=True)
124124

125125
# Caret range
126-
m = CARET_CONSTRAINT.match(constraint)
127-
if m:
126+
127+
if m := CARET_CONSTRAINT.match(constraint):
128128
try:
129129
version = Version.parse(m.group("version"))
130130
except InvalidVersion as e:
@@ -135,8 +135,7 @@ def parse_single_constraint(
135135
return VersionRange(version, version.next_breaking(), include_min=True)
136136

137137
# X Range
138-
m = X_CONSTRAINT.match(constraint)
139-
if m:
138+
if m := X_CONSTRAINT.match(constraint):
140139
op = m.group("op")
141140

142141
try:
@@ -149,8 +148,7 @@ def parse_single_constraint(
149148
raise ValueError(f"Could not parse version constraint: {constraint}")
150149

151150
# Basic comparator
152-
m = BASIC_CONSTRAINT.match(constraint)
153-
if m:
151+
if m := BASIC_CONSTRAINT.match(constraint):
154152
op = m.group("op")
155153
version_string = m.group("version")
156154

@@ -163,7 +161,6 @@ def parse_single_constraint(
163161
raise ParseConstraintError(
164162
f"Could not parse version constraint: {constraint}"
165163
) from e
166-
167164
if op == "<":
168165
return VersionRange(max=version)
169166
if op == "<=":
@@ -180,6 +177,39 @@ def parse_single_constraint(
180177
is_marker_constraint=is_marker_constraint,
181178
)
182179

180+
if op == "!=":
181+
return VersionUnion(VersionRange(max=version), VersionRange(min=version))
182+
return version
183+
184+
# These below should be reserved for comparing non python packages such as OS
185+
# versions using `platform_release`
186+
if m := BASIC_RELEASE_CONSTRAINT.match(constraint):
187+
op = m.group("op")
188+
major = m.group("major")
189+
minor = m.group("minor")
190+
patch = m.group("patch")
191+
# certain OS releases aren't semver or pep440 compliant
192+
build = m.group("build")
193+
try:
194+
version = Version.from_parts(
195+
major=int(major),
196+
minor=int(minor) if minor else None,
197+
patch=int(patch) if patch else None,
198+
post=ReleaseTag(phase=build),
199+
)
200+
except InvalidVersion as e:
201+
raise ParseConstraintError(
202+
f"Could not parse version constraint: {constraint}"
203+
) from e
204+
205+
if op == "<":
206+
return VersionRange(max=version)
207+
if op == "<=":
208+
return VersionRange(max=version, include_max=True)
209+
if op == ">":
210+
return VersionRange(min=version)
211+
if op == ">=":
212+
return VersionRange(min=version, include_min=True)
183213
if op == "!=":
184214
return VersionUnion(VersionRange(max=version), VersionRange(min=version))
185215

src/poetry/core/constraints/version/patterns.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,24 @@
55
from packaging.version import VERSION_PATTERN
66

77

8+
RELEASE_PATTERN = r"""
9+
(?P<major>0|[1-9]\d*)
10+
(?:
11+
\.
12+
(?P<minor>0|[1-9]\d*)
13+
(?:
14+
\.
15+
(?P<patch>0|[1-9]\d*)
16+
(?P<nonstd>(?:\.(0|[1-9]\d*))*)?
17+
)
18+
)
19+
(?:\+|-(?P<build>
20+
[0-9a-zA-Z-]+
21+
(?:\.[0-9a-zA-Z-]+)*
22+
))?
23+
"""
24+
25+
826
COMPLETE_VERSION = re.compile(VERSION_PATTERN, re.VERBOSE | re.IGNORECASE)
927

1028
CARET_CONSTRAINT = re.compile(
@@ -20,9 +38,15 @@
2038
r"^(?P<op>!=|==)?\s*v?(?P<version>(\d+)(?:\.(\d+))?(?:\.(\d+))?)(?:\.[xX*])+$"
2139
)
2240

41+
2342
# note that we also allow technically incorrect version patterns with astrix (eg: 3.5.*)
2443
# as this is supported by pip and appears in metadata within python packages
2544
BASIC_CONSTRAINT = re.compile(
2645
rf"^(?P<op><>|!=|>=?|<=?|==?)?\s*(?P<version>{VERSION_PATTERN}|dev)(?P<wildcard>\.\*)?$",
2746
re.VERBOSE | re.IGNORECASE,
2847
)
48+
49+
BASIC_RELEASE_CONSTRAINT = re.compile(
50+
rf"^(?P<op><>|!=|>=?|<=?|==?)?\s*(?P<version>{RELEASE_PATTERN})$",
51+
re.VERBOSE | re.IGNORECASE,
52+
)

tests/version/test_markers.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -887,14 +887,6 @@ def test_multi_marker_removes_duplicates() -> None:
887887
@pytest.mark.parametrize(
888888
("marker_string", "environment", "expected"),
889889
[
890-
('"tegra" in platform_machine', {"platform_machine": "5.10.120-tegra"}, True),
891-
('"tegra" in platform_machine', {"platform_machine": "5.10.120"}, False),
892-
(
893-
'"tegra" not in platform_machine',
894-
{"platform_machine": "5.10.120-tegra"},
895-
False,
896-
),
897-
('"tegra" not in platform_machine', {"platform_machine": "5.10.120"}, True),
898890
(f"os_name == '{os.name}'", None, True),
899891
("os_name == 'foo'", {"os_name": "foo"}, True),
900892
("os_name == 'foo'", {"os_name": "bar"}, False),
@@ -924,6 +916,24 @@ def test_multi_marker_removes_duplicates() -> None:
924916
("sys.platform == 'win32'", {"sys_platform": "linux2"}, False),
925917
("platform.version in 'Ubuntu'", {"platform_version": "#39"}, False),
926918
("platform.machine=='x86_64'", {"platform_machine": "x86_64"}, True),
919+
('"tegra" in platform_machine', {"platform_machine": "5.10.120-tegra"}, True),
920+
('"tegra" in platform_machine', {"platform_machine": "5.10.120"}, False),
921+
(
922+
'"tegra" not in platform_machine',
923+
{"platform_machine": "5.10.120-tegra"},
924+
False,
925+
),
926+
('"tegra" not in platform_machine', {"platform_machine": "5.10.120"}, True),
927+
(
928+
"platform_release != '4.9.253-tegra'",
929+
{"platform_release": "4.9.254-tegra"},
930+
True,
931+
),
932+
(
933+
"platform_release < '5.10.123-tegra' and platform_release >= '4.9.254-tegra'",
934+
{"platform_release": "4.9.254-tegra"},
935+
True,
936+
),
927937
(
928938
"platform.python_implementation=='Jython'",
929939
{"platform_python_implementation": "CPython"},

0 commit comments

Comments
 (0)