예제 #1
0
    def union(self, other):  # type: (VersionConstraint) -> VersionConstraint
        from pipgrip.libs.semver.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, VersionRange):
            # 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)
예제 #2
0
파일: __init__.py 프로젝트: bryder/pipgrip
def parse_constraint(constraints):  # type: (str) -> VersionConstraint
    if constraints == "*":
        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:
        return VersionUnion.of(*or_groups)
예제 #3
0
    def union(self, other):  # type: (VersionConstraint) -> VersionConstraint
        from pipgrip.libs.semver.version_range import VersionRange

        if other.allows(self):
            return other

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

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

        return VersionUnion.of(self, other)
예제 #4
0
파일: __init__.py 프로젝트: bryder/pipgrip
def parse_single_constraint(constraint):  # type: (str) -> VersionConstraint
    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(1))

        high = version.stable.next_minor
        if len(m.group(1).split(".")) == 1:
            high = version.stable.next_major

        return VersionRange(
            version, high, include_min=True, always_include_max_prerelease=True
        )

    # PEP 440 Tilde range (~=)
    m = TILDE_PEP440_CONSTRAINT.match(constraint)
    if m:
        precision = 1
        if m.group(3):
            precision += 1

            if m.group(4):
                precision += 1

        version = Version.parse(m.group(1))

        if precision == 2:
            low = version
            high = version.stable.next_major
        else:
            low = version
            high = version.stable.next_minor

        return VersionRange(
            low, high, include_min=True, always_include_max_prerelease=True
        )

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

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

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

        if minor is not None:
            version = Version(major, int(minor), 0)

            result = VersionRange(
                version,
                version.next_minor,
                include_min=True,
                always_include_max_prerelease=True,
            )
        else:
            if major == 0:
                result = VersionRange(max=Version(1, 0, 0))
            else:
                version = Version(major, 0, 0)

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

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

        return result

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

        if version == "dev":
            version = "0.0-dev"

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

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

    raise ValueError("Could not parse version constraint: {}".format(constraint))
예제 #5
0
    def difference(self, other):  # type: (VersionConstraint) -> VersionConstraint
        from pipgrip.libs.semver.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 = []  # type: 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))