Skip to content

Commit

Permalink
fix construction of python version marker
Browse files Browse the repository at this point in the history
  • Loading branch information
dimbleby committed Aug 29, 2022
1 parent e8cb613 commit 6c07428
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 42 deletions.
6 changes: 2 additions & 4 deletions src/poetry/core/packages/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from poetry.core.packages.dependency_group import MAIN_GROUP
from poetry.core.packages.specification import PackageSpecification
from poetry.core.packages.utils.utils import create_nested_marker
from poetry.core.packages.utils.utils import get_python_constraint_from_marker
from poetry.core.semver.helpers import parse_constraint
from poetry.core.version.markers import parse_marker

Expand Down Expand Up @@ -263,11 +262,10 @@ def python_versions(self) -> str:
@python_versions.setter
def python_versions(self, value: str) -> None:
self._python_versions = value
constraint = parse_constraint(value)
self._python_constraint = parse_constraint(value)
self._python_marker = parse_marker(
create_nested_marker("python_version", constraint)
create_nested_marker("python_version", self._python_constraint)
)
self._python_constraint = get_python_constraint_from_marker(self._python_marker)

@property
def python_constraint(self) -> VersionConstraint:
Expand Down
83 changes: 48 additions & 35 deletions src/poetry/core/packages/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,44 +240,57 @@ def create_nested_marker(
marker = f'{name} == "{constraint.text}"'
else:
assert isinstance(constraint, VersionRange)
min_name = max_name = name

parts = []

# `python_version` is a special case: to keep the constructed marker equivalent
# to the constraint we need to be careful with the precision.
#
# PEP 440 tells us that that when we come to make the comparison the release
# segment will be zero padded: eg "<= 3.10" is equivalent to "<= 3.10.0".
#
# But "python_version <= 3.10" is _not_ equivalent to "python_version <= 3.10.0" -
# see normalize_python_version_markers.
#
# A similar issue arises for a constraint like "> 3.6".
if constraint.min is not None:
op = ">="
if not constraint.include_min:
op = ">"

op = ">=" if constraint.include_min else ">"
version = constraint.min
if constraint.max is not None:
min_name = max_name = name
if min_name == "python_version" and constraint.min.precision >= 3:
min_name = "python_full_version"

if max_name == "python_version" and constraint.max.precision >= 3:
max_name = "python_full_version"

text = f'{min_name} {op} "{version}"'

op = "<="
if not constraint.include_max:
op = "<"

version = constraint.max

text += f' and {max_name} {op} "{version}"'

return text
elif constraint.max is not None:
op = "<="
if not constraint.include_max:
op = "<"

if min_name == "python_version" and version.precision >= 3:
min_name = "python_full_version"

if (
min_name == "python_version"
and not constraint.include_min
and version.precision < 3
):
padding = ".0" * (3 - version.precision)
part = f'python_full_version > "{version}{padding}"'
else:
part = f'{min_name} {op} "{version}"'

parts.append(part)

if constraint.max is not None:
op = "<=" if constraint.include_max else "<"
version = constraint.max
else:
return ""

if name == "python_version" and version.precision >= 3:
name = "python_full_version"

marker = f'{name} {op} "{version}"'
if max_name == "python_version" and version.precision >= 3:
max_name = "python_full_version"

if (
name == "python_version"
and constraint.include_max
and version.precision < 3
):
padding = ".0" * (3 - version.precision)
part = f'python_full_version <= "{version}{padding}"'
else:
part = f'{max_name} {op} "{version}"'

parts.append(part)

marker = " and ".join(parts)

return marker

Expand Down
6 changes: 3 additions & 3 deletions tests/packages/test_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,15 +533,15 @@ def test_package_pep592_yanked(
assert package.yanked_reason == expected_yanked_reason


def test_python_versions_are_normalized() -> None:
def test_python_versions_are_made_precise() -> None:
package = Package("foo", "1.2.3")
package.python_versions = ">3.6,<=3.10"

assert (
str(package.python_marker)
== 'python_version > "3.6" and python_version <= "3.10"'
== 'python_full_version > "3.6.0" and python_full_version <= "3.10.0"'
)
assert str(package.python_constraint) == ">=3.7,<3.11"
assert str(package.python_constraint) == ">3.6,<=3.10"


def test_cannot_update_package_version() -> None:
Expand Down

0 comments on commit 6c07428

Please sign in to comment.