Skip to content

Commit

Permalink
Merge pull request python-poetry#208 from python-poetry/fix-marker-to…
Browse files Browse the repository at this point in the history
…-python-constraint

Ensure setting dependency marker sets the python constraint
  • Loading branch information
sdispater authored Sep 21, 2021
2 parents 6dbafd4 + 63f994d commit cc12d8f
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 55 deletions.
4 changes: 2 additions & 2 deletions poetry/core/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ def create_dependency(
from .packages.url_dependency import URLDependency
from .packages.utils.utils import create_nested_marker
from .packages.vcs_dependency import VCSDependency
from .semver.helpers import parse_constraint
from .version.markers import AnyMarker
from .version.markers import parse_marker

Expand Down Expand Up @@ -340,11 +341,10 @@ def create_dependency(
if not markers:
marker = AnyMarker()
if python_versions:
dependency.python_versions = python_versions
marker = marker.intersect(
parse_marker(
create_nested_marker(
"python_version", dependency.python_constraint
"python_version", parse_constraint(python_versions)
)
)
)
Expand Down
116 changes: 65 additions & 51 deletions poetry/core/packages/dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def __init__(
self._activated = not self._optional

self.is_root = False
self.marker = AnyMarker()
self._marker = AnyMarker()
self.source_name = None

@property
Expand Down Expand Up @@ -131,7 +131,7 @@ def python_versions(self, value: str) -> None:
self._python_versions = value
self._python_constraint = parse_constraint(value)
if not self._python_constraint.is_any():
self.marker = self.marker.intersect(
self._marker = self._marker.intersect(
parse_marker(
self._create_nested_marker(
"python_version", self._python_constraint
Expand All @@ -151,6 +151,69 @@ def transitive_python_versions(self, value: str) -> None:
self._transitive_python_versions = value
self._transitive_python_constraint = parse_constraint(value)

@property
def marker(self) -> "BaseMarker":
return self._marker

@marker.setter
def marker(self, marker: Union[str, "BaseMarker"]) -> None:
from poetry.core.semver.helpers import parse_constraint
from poetry.core.version.markers import BaseMarker
from poetry.core.version.markers import parse_marker

from .utils.utils import convert_markers

if not isinstance(marker, BaseMarker):
marker = parse_marker(marker)

self._marker = marker

markers = convert_markers(marker)

if "extra" in markers:
# If we have extras, the dependency is optional
self.deactivate()

for or_ in markers["extra"]:
for _, extra in or_:
self.in_extras.append(extra)

if "python_version" in markers:
ors = []
for or_ in markers["python_version"]:
ands = []
for op, version in or_:
# Expand python version
if op == "==" and "*" not in version:
version = "~" + version
op = ""
elif op == "!=":
version += ".*"
elif op in ("in", "not in"):
versions = []
for v in re.split("[ ,]+", version):
split = v.split(".")
if len(split) in [1, 2]:
split.append("*")
op_ = "" if op == "in" else "!="
else:
op_ = "==" if op == "in" else "!="

versions.append(op_ + ".".join(split))

glue = " || " if op == "in" else ", "
if versions:
ands.append(glue.join(versions))

continue

ands.append("{}{}".format(op, version))

ors.append(" ".join(ands))

self._python_versions = " || ".join(ors)
self._python_constraint = parse_constraint(self._python_versions)

@property
def transitive_marker(self) -> "BaseMarker":
if self._transitive_marker is None:
Expand Down Expand Up @@ -427,7 +490,6 @@ def create_from_pep_508(

from .url_dependency import URLDependency
from .utils.link import Link
from .utils.utils import convert_markers
from .utils.utils import is_archive_file
from .utils.utils import is_installable_dir
from .utils.utils import is_url
Expand All @@ -446,11 +508,6 @@ def create_from_pep_508(

req = Requirement(name)

if req.marker:
markers = convert_markers(req.marker)
else:
markers = {}

name = req.name
path = os.path.normpath(os.path.abspath(name))
link = None
Expand Down Expand Up @@ -543,49 +600,6 @@ def create_from_pep_508(

dep = Dependency(name, constraint, extras=req.extras)

if "extra" in markers:
# If we have extras, the dependency is optional
dep.deactivate()

for or_ in markers["extra"]:
for _, extra in or_:
dep.in_extras.append(extra)

if "python_version" in markers:
ors = []
for or_ in markers["python_version"]:
ands = []
for op, version in or_:
# Expand python version
if op == "==" and "*" not in version:
version = "~" + version
op = ""
elif op == "!=":
version += ".*"
elif op in ("in", "not in"):
versions = []
for v in re.split("[ ,]+", version):
split = v.split(".")
if len(split) in [1, 2]:
split.append("*")
op_ = "" if op == "in" else "!="
else:
op_ = "==" if op == "in" else "!="

versions.append(op_ + ".".join(split))

glue = " || " if op == "in" else ", "
if versions:
ands.append(glue.join(versions))

continue

ands.append("{}{}".format(op, version))

ors.append(" ".join(ands))

dep.python_versions = " || ".join(ors)

if req.marker:
dep.marker = req.marker

Expand Down
8 changes: 8 additions & 0 deletions tests/packages/test_dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,11 @@ def test_with_constraint():
assert new.transitive_marker == dependency.transitive_marker
assert new.python_constraint == dependency.python_constraint
assert new.transitive_python_constraint == dependency.transitive_python_constraint


def test_marker_properly_sets_python_constraint():
dependency = Dependency("foo", "^1.2.3")

dependency.marker = 'python_version >= "3.6" and python_version < "4.0"'

assert str(dependency.python_constraint) == ">=3.6,<4.0"
4 changes: 2 additions & 2 deletions tests/test_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def test_create_poetry():

pathlib2 = dependencies["pathlib2"]
assert pathlib2.pretty_constraint == "^2.2"
assert pathlib2.python_versions == "~2.7"
assert pathlib2.python_versions == ">=2.7 <2.8"
assert not pathlib2.is_optional()

demo = dependencies["demo"]
Expand Down Expand Up @@ -102,7 +102,7 @@ def test_create_poetry():
dataclasses = dependencies["dataclasses"]
assert dataclasses.name == "dataclasses"
assert dataclasses.pretty_constraint == "^0.7"
assert dataclasses.python_versions == ">=3.6.1,<3.7"
assert dataclasses.python_versions == ">=3.6.1 <3.7"
assert (
str(dataclasses.marker)
== 'python_full_version >= "3.6.1" and python_version < "3.7"'
Expand Down

0 comments on commit cc12d8f

Please sign in to comment.