Skip to content

Commit

Permalink
Merge pull request #21 from python-poetry/markers-improvements
Browse files Browse the repository at this point in the history
Add support for markers inverse
  • Loading branch information
sdispater committed Apr 12, 2020
2 parents 9c4cdc9 + 5dbee6e commit a315bce
Show file tree
Hide file tree
Showing 3 changed files with 753 additions and 2 deletions.
87 changes: 85 additions & 2 deletions poetry/core/version/markers.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ def exclude(self, marker_name): # type: (str) -> BaseMarker
def only(self, marker_name): # type: (str) -> BaseMarker
raise NotImplementedError()

def invert(self): # type: () -> BaseMarker
raise NotImplementedError()

def __repr__(self):
return "<{} {}>".format(self.__class__.__name__, str(self))

Expand Down Expand Up @@ -210,6 +213,9 @@ def exclude(self, marker_name): # type: (str) -> AnyMarker
def only(self, marker_name): # type: (str) -> AnyMarker
return self

def invert(self): # type: () -> EmptyMarker
return EmptyMarker()

def __str__(self):
return ""

Expand Down Expand Up @@ -251,6 +257,9 @@ def exclude(self, marker_name): # type: (str) -> EmptyMarker
def only(self, marker_name): # type: (str) -> EmptyMarker
return self

def invert(self): # type: () -> AnyMarker
return AnyMarker()

def __str__(self):
return "<empty>"

Expand All @@ -269,7 +278,7 @@ def __eq__(self, other):

class SingleMarker(BaseMarker):

_CONSTRAINT_RE = re.compile(r"(?i)^(~=|!=|>=?|<=?|==?|in|not in)?\s*(.+)$")
_CONSTRAINT_RE = re.compile(r"(?i)^(~=|!=|>=?|<=?|==?=?|in|not in)?\s*(.+)$")
_VERSION_LIKE_MARKER_NAME = {"python_version", "platform_release"}

def __init__(self, name, constraint):
Expand Down Expand Up @@ -393,6 +402,51 @@ def only(self, marker_name): # type: (str) -> BaseMarker

return self

def invert(self): # type: () -> BaseMarker
if self._operator in ("===", "=="):
operator = "!="
elif self._operator == "!=":
operator = "=="
elif self._operator == ">":
operator = "<="
elif self._operator == ">=":
operator = "<"
elif self._operator == "<":
operator = ">="
elif self._operator == "<=":
operator = ">"
elif self._operator == "in":
operator = "not in"
elif self._operator == "not in":
operator = "in"
elif self._operator == "~=":
# This one is more tricky to handle
# since it's technically a multi marker
# so the inverse will be a union of inverse
from poetry.core.semver import VersionRange

if not isinstance(self._constraint, VersionRange):
# The constraint must be a version range, otherwise
# it's an internal error
raise RuntimeError(
"The '~=' operator should only represent version ranges"
)

min_ = self._constraint.min
min_operator = ">=" if self._constraint.include_min else "<"
max_ = self._constraint.max
max_operator = "<=" if self._constraint.include_max else "<"

return MultiMarker.of(
SingleMarker(self._name, "{} {}".format(min_operator, min_)),
SingleMarker(self._name, "{} {}".format(max_operator, max_)),
).invert()
else:
# We should never go there
raise RuntimeError("Invalid marker operator '{}'".format(self._operator))

return parse_marker("{} {} '{}'".format(self._name, operator, self._value))

def __eq__(self, other):
if not isinstance(other, SingleMarker):
return False
Expand Down Expand Up @@ -440,6 +494,9 @@ def of(cls, *markers):
if marker in new_markers:
continue

if marker.is_any():
continue

if isinstance(marker, SingleMarker):
intersected = False
for i, mark in enumerate(new_markers):
Expand Down Expand Up @@ -533,6 +590,11 @@ def only(self, marker_name): # type: (str) -> BaseMarker

return self.of(*new_markers)

def invert(self): # type: () -> MarkerUnion
markers = [marker.invert() for marker in self._markers]

return MarkerUnion.of(*markers)

def __eq__(self, other):
if not isinstance(other, MultiMarker):
return False
Expand Down Expand Up @@ -568,7 +630,7 @@ def markers(self):
return self._markers

@classmethod
def of(cls, *markers): # type: (tuple) -> MarkerUnion
def of(cls, *markers): # type: (BaseMarker) -> MarkerUnion
flattened_markers = _flatten_markers(markers, MarkerUnion)

markers = []
Expand Down Expand Up @@ -603,6 +665,22 @@ def of(cls, *markers): # type: (tuple) -> MarkerUnion
if any(m.is_any() for m in markers):
return AnyMarker()

to_delete_indices = set()
for i, marker in enumerate(markers):
for j, m in enumerate(markers):
if m.invert() == marker:
to_delete_indices.add(i)
to_delete_indices.add(j)

for idx in reversed(sorted(to_delete_indices)):
del markers[idx]

if not markers:
return AnyMarker()

if len(markers) == 1:
return markers[0]

return MarkerUnion(*markers)

def append(self, marker):
Expand Down Expand Up @@ -686,6 +764,11 @@ def only(self, marker_name): # type: (str) -> BaseMarker

return self.of(*new_markers)

def invert(self): # type: () -> MultiMarker
markers = [marker.invert() for marker in self._markers]

return MultiMarker.of(*markers)

def __eq__(self, other):
if not isinstance(other, MarkerUnion):
return False
Expand Down
Empty file added tests/version/__init__.py
Empty file.
Loading

0 comments on commit a315bce

Please sign in to comment.