Skip to content

Commit

Permalink
add support for non Python versions in platform_release markers (#722)
Browse files Browse the repository at this point in the history
e.g. 'platform_release == "4.9.253-tegra"'

Co-authored-by: Randy Döring <[email protected]>
  • Loading branch information
npapapietro and radoering committed Jul 27, 2024
1 parent 849bfaa commit 61f1a48
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 11 deletions.
50 changes: 44 additions & 6 deletions src/poetry/core/constraints/version/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,16 @@ def parse_constraint(constraints: str) -> VersionConstraint:
return _parse_constraint(constraints=constraints)


def parse_marker_version_constraint(constraints: str) -> VersionConstraint:
return _parse_constraint(constraints=constraints, is_marker_constraint=True)
def parse_marker_version_constraint(
constraints: str, *, pep440: bool = True
) -> VersionConstraint:
return _parse_constraint(
constraints=constraints, is_marker_constraint=True, pep440=pep440
)


def _parse_constraint(
constraints: str, *, is_marker_constraint: bool = False
constraints: str, *, is_marker_constraint: bool = False, pep440: bool = True
) -> VersionConstraint:
if constraints == "*":
from poetry.core.constraints.version.version_range import VersionRange
Expand All @@ -46,13 +50,17 @@ def _parse_constraint(
for constraint in and_constraints:
constraint_objects.append(
parse_single_constraint(
constraint, is_marker_constraint=is_marker_constraint
constraint,
is_marker_constraint=is_marker_constraint,
pep440=pep440,
)
)
else:
constraint_objects.append(
parse_single_constraint(
and_constraints[0], is_marker_constraint=is_marker_constraint
and_constraints[0],
is_marker_constraint=is_marker_constraint,
pep440=pep440,
)
)

Expand All @@ -74,9 +82,10 @@ def _parse_constraint(


def parse_single_constraint(
constraint: str, *, is_marker_constraint: bool = False
constraint: str, *, is_marker_constraint: bool = False, pep440: bool = True
) -> VersionConstraint:
from poetry.core.constraints.version.patterns import BASIC_CONSTRAINT
from poetry.core.constraints.version.patterns import BASIC_RELEASE_CONSTRAINT
from poetry.core.constraints.version.patterns import CARET_CONSTRAINT
from poetry.core.constraints.version.patterns import TILDE_CONSTRAINT
from poetry.core.constraints.version.patterns import TILDE_PEP440_CONSTRAINT
Expand Down Expand Up @@ -185,6 +194,35 @@ def parse_single_constraint(

return version

# These below should be reserved for comparing non python packages such as OS
# versions using `platform_release`
if not pep440 and (m := BASIC_RELEASE_CONSTRAINT.match(constraint)):
op = m.group("op")
release_string = m.group("release")
build = m.group("build")

try:
version = Version(
release=Version.parse(release_string).release,
local=build,
)
except InvalidVersion as e:
raise ParseConstraintError(
f"Could not parse version constraint: {constraint}"
) from e

if op == "<":
return VersionRange(max=version)
if op == "<=":
return VersionRange(max=version, include_max=True)
if op == ">":
return VersionRange(min=version)
if op == ">=":
return VersionRange(min=version, include_min=True)
if op == "!=":
return VersionUnion(VersionRange(max=version), VersionRange(min=version))
return version

raise ParseConstraintError(f"Could not parse version constraint: {constraint}")


Expand Down
14 changes: 14 additions & 0 deletions src/poetry/core/constraints/version/patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,17 @@
rf"^(?P<op><>|!=|>=?|<=?|==?)?\s*(?P<version>{VERSION_PATTERN}|dev)(?P<wildcard>\.\*)?$",
re.VERBOSE | re.IGNORECASE,
)

RELEASE_PATTERN = r"""
(?P<release>[0-9]+(?:\.[0-9]+)*)
(?:(\+|-)(?P<build>
[0-9a-zA-Z-]+
(?:\.[0-9a-zA-Z-]+)*
))?
"""

# pattern for non Python versions such as OS versions in `platform_release`
BASIC_RELEASE_CONSTRAINT = re.compile(
rf"^(?P<op><>|!=|>=?|<=?|==?)?\s*(?P<version>{RELEASE_PATTERN})$",
re.VERBOSE | re.IGNORECASE,
)
12 changes: 7 additions & 5 deletions src/poetry/core/version/markers.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,15 +216,15 @@ def __init__(self, name: str, constraint: SingleMarkerConstraint) -> None:
from poetry.core.constraints.generic import (
parse_constraint as parse_generic_constraint,
)
from poetry.core.constraints.version import (
parse_constraint as parse_version_constraint,
)
from poetry.core.constraints.version import parse_marker_version_constraint

self._name = ALIASES.get(name, name)
self._constraint = constraint
self._parser: Callable[[str], BaseConstraint | VersionConstraint]
if isinstance(constraint, VersionConstraint):
self._parser = parse_version_constraint
self._parser = functools.partial(
parse_marker_version_constraint, pep440=name != "platform_release"
)
else:
self._parser = parse_generic_constraint

Expand Down Expand Up @@ -364,7 +364,9 @@ def __init__(
# or `"arm" not in platform_version`.
pass
elif name in self._VERSION_LIKE_MARKER_NAME:
parser = parse_marker_version_constraint
parser = functools.partial(
parse_marker_version_constraint, pep440=name != "platform_release"
)

if self._operator in {"in", "not in"}:
versions = []
Expand Down
13 changes: 13 additions & 0 deletions tests/constraints/version/test_parse_constraint.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from poetry.core.constraints.version import VersionRange
from poetry.core.constraints.version import VersionUnion
from poetry.core.constraints.version import parse_constraint
from poetry.core.constraints.version import parse_marker_version_constraint
from poetry.core.constraints.version.exceptions import ParseConstraintError
from poetry.core.version.pep440 import ReleaseTag


Expand Down Expand Up @@ -595,3 +597,14 @@ def test_parse_constraint_with_white_space_padding(
padding = " " * (4 if with_whitespace_padding else 0)
constraint = padding.join(["", *constraint_parts, ""])
assert parse_constraint(constraint) == expected


def test_parse_marker_constraint_does_not_allow_invalid_version() -> None:
with pytest.raises(ParseConstraintError):
parse_marker_version_constraint("4.9.253-tegra")


def test_parse_marker_constraint_does_allow_invalid_version_if_requested() -> None:
assert parse_marker_version_constraint(
"4.9.253-tegra", pep440=False
) == Version.from_parts(4, 9, 253, local="tegra")
49 changes: 49 additions & 0 deletions tests/version/test_markers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from poetry.core.version.markers import AnyMarker
from poetry.core.version.markers import AtomicMarkerUnion
from poetry.core.version.markers import EmptyMarker
from poetry.core.version.markers import InvalidMarker
from poetry.core.version.markers import MarkerUnion
from poetry.core.version.markers import MultiMarker
from poetry.core.version.markers import SingleMarker
Expand Down Expand Up @@ -72,6 +73,21 @@ def test_parse_marker(marker: str) -> None:
assert str(parse_marker(marker)) == marker


@pytest.mark.parametrize(
("marker", "valid"),
[
('platform_release != "4.9.253-tegra"', True),
('python_version != "4.9.253-tegra"', False),
],
)
def test_parse_marker_non_python_versions(marker: str, valid: bool) -> None:
if valid:
assert str(parse_marker(marker)) == marker
else:
with pytest.raises(InvalidMarker):
parse_marker(marker)


@pytest.mark.parametrize(
("marker", "expected_name", "expected_constraint"),
[
Expand Down Expand Up @@ -962,6 +978,39 @@ def test_multi_marker_removes_duplicates() -> None:
{"platform_machine": "x86_64"},
False,
),
('"tegra" in platform_release', {"platform_release": "5.10.120-tegra"}, True),
('"tegra" in platform_release', {"platform_release": "5.10.120"}, False),
(
'"tegra" not in platform_release',
{"platform_release": "5.10.120-tegra"},
False,
),
('"tegra" not in platform_release', {"platform_release": "5.10.120"}, True),
(
"platform_machine == 'aarch64' and 'tegra' in platform_release",
{"platform_release": "5.10.120-tegra", "platform_machine": "aarch64"},
True,
),
(
"platform_release != '4.9.253-tegra'",
{"platform_release": "4.9.254-tegra"},
True,
),
(
"platform_release != '4.9.253-tegra'",
{"platform_release": "4.9.253"},
True,
),
(
"platform_release >= '6.6.0+rpt-rpi-v8'",
{"platform_release": "6.6.20+rpt-rpi-v8"},
True,
),
(
"platform_release < '5.10.123-tegra' and platform_release >= '4.9.254-tegra'",
{"platform_release": "4.9.254-tegra"},
True,
),
# extras
# single extra
("extra == 'security'", {"extra": "quux"}, False),
Expand Down

0 comments on commit 61f1a48

Please sign in to comment.