Esempio n. 1
0
    def union(self, other: "VersionTypes") -> "VersionTypes":
        from .version import Version

        if isinstance(other, Version):
            if self.allows(other):
                return self

            if other == self.min:
                return VersionRange(self.min,
                                    self.max,
                                    include_min=True,
                                    include_max=self.include_max)

            if other == self.max:
                return VersionRange(self.min,
                                    self.max,
                                    include_min=self.include_min,
                                    include_max=True)

            return VersionUnion.of(self, other)

        if isinstance(other, VersionRangeConstraint):
            # If the two ranges don't overlap, we won't be able to create a single
            # VersionRange for both of them.
            edges_touch = (self.max == other.min and
                           (self.include_max or other.include_min)) or (
                               self.min == other.max and
                               (self.include_min or other.include_max))

            if not edges_touch and not self.allows_any(other):
                return VersionUnion.of(self, other)

            if self.allows_lower(other):
                union_min = self.min
                union_include_min = self.include_min
            else:
                union_min = other.min
                union_include_min = other.include_min

            if self.allows_higher(other):
                union_max = self.max
                union_include_max = self.include_max
            else:
                union_max = other.max
                union_include_max = other.include_max

            return VersionRange(
                union_min,
                union_max,
                include_min=union_include_min,
                include_max=union_include_max,
            )

        return VersionUnion.of(self, other)
Esempio n. 2
0
def parse_constraint(constraints: str) -> VersionConstraint:
    if constraints == "*":
        from poetry.core.semver.version_range import VersionRange

        return VersionRange()

    or_constraints = re.split(r"\s*\|\|?\s*", constraints.strip())
    or_groups = []
    for constraints in or_constraints:
        and_constraints = re.split(
            "(?<!^)(?<![~=>< ,]) *(?<!-)[, ](?!-) *(?!,|$)", constraints)
        constraint_objects = []

        if len(and_constraints) > 1:
            for constraint in and_constraints:
                constraint_objects.append(parse_single_constraint(constraint))
        else:
            constraint_objects.append(
                parse_single_constraint(and_constraints[0]))

        if len(constraint_objects) == 1:
            constraint = constraint_objects[0]
        else:
            constraint = constraint_objects[0]
            for next_constraint in constraint_objects[1:]:
                constraint = constraint.intersect(next_constraint)

        or_groups.append(constraint)

    if len(or_groups) == 1:
        return or_groups[0]
    else:
        from poetry.core.semver.version_union import VersionUnion

        return VersionUnion.of(*or_groups)
Esempio n. 3
0
def test_parse_constraint_multi_wilcard(input):
    assert parse_constraint(input) == VersionUnion(
        VersionRange(
            Version.from_parts(2, 7, 0), Version.from_parts(3, 0, 0), True, False
        ),
        VersionRange(Version.from_parts(3, 2, 0), None, True, False),
    )
Esempio n. 4
0
    def union(self, other: VersionConstraint) -> VersionConstraint:
        from poetry.core.semver.version_range import VersionRange

        if other.allows(self):
            return other

        if isinstance(other, VersionRangeConstraint):
            if self.allows(other.min):
                return VersionRange(
                    other.min,
                    other.max,
                    include_min=True,
                    include_max=other.include_max,
                )

            if self.allows(other.max):
                return VersionRange(
                    other.min,
                    other.max,
                    include_min=other.include_min,
                    include_max=True,
                )

        return VersionUnion.of(self, other)
     "== 3.8",
     VersionRange(
         min=Version.from_parts(3, 8),
         max=Version.from_parts(3, 8),
         include_min=True,
         include_max=True,
     ),
 ),
 (
     "~2.7 || ~3.8",
     VersionUnion(
         VersionRange(
             min=Version.from_parts(2, 7),
             max=Version.from_parts(2, 8),
             include_min=True,
         ),
         VersionRange(
             min=Version.from_parts(3, 8),
             max=Version.from_parts(3, 9),
             include_min=True,
         ),
     ),
 ),
 (
     "~2.7||~3.8",
     VersionUnion(
         VersionRange(
             min=Version.from_parts(2, 7),
             max=Version.from_parts(2, 8),
             include_min=True,
         ),
         VersionRange(
Esempio n. 6
0
def parse_single_constraint(constraint: str) -> VersionConstraint:
    from poetry.core.semver.patterns import BASIC_CONSTRAINT
    from poetry.core.semver.patterns import CARET_CONSTRAINT
    from poetry.core.semver.patterns import TILDE_CONSTRAINT
    from poetry.core.semver.patterns import TILDE_PEP440_CONSTRAINT
    from poetry.core.semver.patterns import X_CONSTRAINT
    from poetry.core.semver.version import Version
    from poetry.core.semver.version_range import VersionRange
    from poetry.core.semver.version_union import VersionUnion

    m = re.match(r"(?i)^v?[xX*](\.[xX*])*$", constraint)
    if m:
        return VersionRange()

    # Tilde range
    m = TILDE_CONSTRAINT.match(constraint)
    if m:
        version = Version.parse(m.group("version"))
        high = version.stable.next_minor()
        if version.release.precision == 1:
            high = version.stable.next_major()

        return VersionRange(version, high, include_min=True)

    # PEP 440 Tilde range (~=)
    m = TILDE_PEP440_CONSTRAINT.match(constraint)
    if m:
        version = Version.parse(m.group("version"))
        if version.release.precision == 2:
            high = version.stable.next_major()
        else:
            high = version.stable.next_minor()

        return VersionRange(version, high, include_min=True)

    # Caret range
    m = CARET_CONSTRAINT.match(constraint)
    if m:
        version = Version.parse(m.group("version"))

        return VersionRange(version, version.next_breaking(), include_min=True)

    # X Range
    m = X_CONSTRAINT.match(constraint)
    if m:
        op = m.group("op")
        major = int(m.group(2))
        minor = m.group(3)

        if minor is not None:
            version = Version.from_parts(major, int(minor), 0)
            result: VersionConstraint = VersionRange(version,
                                                     version.next_minor(),
                                                     include_min=True)
        else:
            if major == 0:
                result = VersionRange(max=Version.from_parts(1, 0, 0))
            else:
                version = Version.from_parts(major, 0, 0)

                result = VersionRange(version,
                                      version.next_major(),
                                      include_min=True)

        if op == "!=":
            result = VersionRange().difference(result)

        return result

    # Basic comparator
    m = BASIC_CONSTRAINT.match(constraint)
    if m:
        op = m.group("op")
        version_string = m.group("version")

        if version_string == "dev":
            version_string = "0.0-dev"

        try:
            version = Version.parse(version_string)
        except ValueError:
            raise ValueError(
                f"Could not parse version constraint: {constraint}")

        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

    from poetry.core.semver.exceptions import ParseConstraintError

    raise ParseConstraintError(
        f"Could not parse version constraint: {constraint}")
Esempio n. 7
0
    def difference(self, other: "VersionTypes") -> "VersionTypes":
        from .version import Version

        if other.is_empty():
            return self

        if isinstance(other, Version):
            if not self.allows(other):
                return self

            if other == self.min:
                if not self.include_min:
                    return self

                return VersionRange(self.min, self.max, False, self.include_max)

            if other == self.max:
                if not self.include_max:
                    return self

                return VersionRange(self.min, self.max, self.include_min, False)

            return VersionUnion.of(
                VersionRange(self.min, other, self.include_min, False),
                VersionRange(other, self.max, False, self.include_max),
            )
        elif isinstance(other, VersionRange):
            if not self.allows_any(other):
                return self

            if not self.allows_lower(other):
                before = None
            elif self.min == other.min:
                before = self.min
            else:
                before = VersionRange(
                    self.min, other.min, self.include_min, not other.include_min
                )

            if not self.allows_higher(other):
                after = None
            elif self.max == other.max:
                after = self.max
            else:
                after = VersionRange(
                    other.max, self.max, not other.include_max, self.include_max
                )

            if before is None and after is None:
                return EmptyConstraint()

            if before is None:
                return after

            if after is None:
                return before

            return VersionUnion.of(before, after)
        elif isinstance(other, VersionUnion):
            ranges: List[VersionRange] = []
            current = self

            for range in other.ranges:
                # Skip any ranges that are strictly lower than [current].
                if range.is_strictly_lower(current):
                    continue

                # If we reach a range strictly higher than [current], no more ranges
                # will be relevant so we can bail early.
                if range.is_strictly_higher(current):
                    break

                difference = current.difference(range)
                if difference.is_empty():
                    return EmptyConstraint()
                elif isinstance(difference, VersionUnion):
                    # If [range] split [current] in half, we only need to continue
                    # checking future ranges against the latter half.
                    ranges.append(difference.ranges[0])
                    current = difference.ranges[-1]
                else:
                    current = difference

            if not ranges:
                return current

            return VersionUnion.of(*(ranges + [current]))

        raise ValueError("Unknown VersionConstraint type {}.".format(other))