-
Notifications
You must be signed in to change notification settings - Fork 259
Refactor constraints structure #482
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
radoering
merged 4 commits into
python-poetry:main
from
radoering:refactor-constraints-structure
Sep 24, 2022
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
2c35cec
refactor: move poetry.core.packages.constraints to poetry.core.constr…
radoering 6885c83
refactor: move poetry.core.semver to poetry.core.constraints.version
radoering ac7a3be
refactor: deprecate poetry.core.packages.constraints and poetry.core.…
radoering cd8b079
refactor: move constraint parsing of generic constraints from __init_…
radoering File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from poetry.core.constraints.generic.any_constraint import AnyConstraint | ||
| from poetry.core.constraints.generic.base_constraint import BaseConstraint | ||
| from poetry.core.constraints.generic.constraint import Constraint | ||
| from poetry.core.constraints.generic.empty_constraint import EmptyConstraint | ||
| from poetry.core.constraints.generic.multi_constraint import MultiConstraint | ||
| from poetry.core.constraints.generic.parser import parse_constraint | ||
| from poetry.core.constraints.generic.union_constraint import UnionConstraint | ||
|
|
||
|
|
||
| __all__ = [ | ||
| "AnyConstraint", | ||
| "BaseConstraint", | ||
| "Constraint", | ||
| "EmptyConstraint", | ||
| "MultiConstraint", | ||
| "UnionConstraint", | ||
| "parse_constraint", | ||
| ] | ||
4 changes: 2 additions & 2 deletions
4
...re/packages/constraints/any_constraint.py → ...ore/constraints/generic/any_constraint.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
.../packages/constraints/empty_constraint.py → ...e/constraints/generic/empty_constraint.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 2 additions & 2 deletions
4
.../packages/constraints/multi_constraint.py → ...e/constraints/generic/multi_constraint.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import re | ||
|
|
||
| from typing import TYPE_CHECKING | ||
|
|
||
| from poetry.core.constraints.generic.any_constraint import AnyConstraint | ||
| from poetry.core.constraints.generic.constraint import Constraint | ||
| from poetry.core.constraints.generic.union_constraint import UnionConstraint | ||
|
|
||
|
|
||
| if TYPE_CHECKING: | ||
| from poetry.core.constraints.generic.base_constraint import BaseConstraint | ||
|
|
||
|
|
||
| BASIC_CONSTRAINT = re.compile(r"^(!?==?)?\s*([^\s]+?)\s*$") | ||
|
|
||
|
|
||
| def parse_constraint(constraints: str) -> BaseConstraint: | ||
| if constraints == "*": | ||
| return AnyConstraint() | ||
|
|
||
| or_constraints = re.split(r"\s*\|\|?\s*", constraints.strip()) | ||
| or_groups = [] | ||
| for constraints in or_constraints: | ||
| and_constraints = re.split( | ||
| r"(?<!^)(?<![=>< ,]) *(?<!-)[, ](?!-) *(?!,|$)", 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 UnionConstraint(*or_groups) | ||
|
|
||
|
|
||
| def parse_single_constraint(constraint: str) -> Constraint: | ||
| # Basic comparator | ||
| m = BASIC_CONSTRAINT.match(constraint) | ||
| if m: | ||
| op = m.group(1) | ||
| if op is None: | ||
| op = "==" | ||
|
|
||
| version = m.group(2).strip() | ||
|
|
||
| return Constraint(version, op) | ||
|
|
||
| raise ValueError(f"Could not parse version constraint: {constraint}") |
8 changes: 4 additions & 4 deletions
8
.../packages/constraints/union_constraint.py → ...e/constraints/generic/union_constraint.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from poetry.core.constraints.version.empty_constraint import EmptyConstraint | ||
| from poetry.core.constraints.version.parser import parse_constraint | ||
| from poetry.core.constraints.version.util import constraint_regions | ||
| from poetry.core.constraints.version.version import Version | ||
| from poetry.core.constraints.version.version_constraint import VersionConstraint | ||
| from poetry.core.constraints.version.version_range import VersionRange | ||
| from poetry.core.constraints.version.version_range_constraint import ( | ||
| VersionRangeConstraint, | ||
| ) | ||
| from poetry.core.constraints.version.version_union import VersionUnion | ||
|
|
||
|
|
||
| __all__ = [ | ||
| "EmptyConstraint", | ||
| "Version", | ||
| "VersionConstraint", | ||
| "VersionRange", | ||
| "VersionRangeConstraint", | ||
| "VersionUnion", | ||
| "constraint_regions", | ||
| "parse_constraint", | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from typing import TYPE_CHECKING | ||
|
|
||
| from poetry.core.constraints.version.version_constraint import VersionConstraint | ||
|
|
||
|
|
||
| if TYPE_CHECKING: | ||
| from poetry.core.constraints.version.version import Version | ||
| from poetry.core.constraints.version.version_range_constraint import ( | ||
| VersionRangeConstraint, | ||
| ) | ||
|
|
||
|
|
||
| class EmptyConstraint(VersionConstraint): | ||
| def is_empty(self) -> bool: | ||
| return True | ||
|
|
||
| def is_any(self) -> bool: | ||
| return False | ||
|
|
||
| def is_simple(self) -> bool: | ||
| return True | ||
|
|
||
| def allows(self, version: Version) -> bool: | ||
| return False | ||
|
|
||
| def allows_all(self, other: VersionConstraint) -> bool: | ||
| return other.is_empty() | ||
|
|
||
| def allows_any(self, other: VersionConstraint) -> bool: | ||
| return False | ||
|
|
||
| def intersect(self, other: VersionConstraint) -> EmptyConstraint: | ||
| return self | ||
|
|
||
| def union(self, other: VersionConstraint) -> VersionConstraint: | ||
| return other | ||
|
|
||
| def difference(self, other: VersionConstraint) -> EmptyConstraint: | ||
| return self | ||
|
|
||
| def flatten(self) -> list[VersionRangeConstraint]: | ||
| return [] | ||
|
|
||
| def __str__(self) -> str: | ||
| return "<empty>" | ||
|
|
||
| def __eq__(self, other: object) -> bool: | ||
| if not isinstance(other, VersionConstraint): | ||
| return False | ||
|
|
||
| return other.is_empty() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| from __future__ import annotations | ||
|
|
||
|
|
||
| class ParseConstraintError(ValueError): | ||
| pass |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import re | ||
|
|
||
| from typing import TYPE_CHECKING | ||
|
|
||
|
|
||
| if TYPE_CHECKING: | ||
| from poetry.core.constraints.version.version_constraint import VersionConstraint | ||
|
|
||
|
|
||
| def parse_constraint(constraints: str) -> VersionConstraint: | ||
| if constraints == "*": | ||
| from poetry.core.constraints.version.version_range import VersionRange | ||
|
|
||
| return VersionRange() | ||
|
|
||
| or_constraints = re.split(r"\s*\|\|?\s*", constraints.strip()) | ||
| or_groups = [] | ||
| for constraints in or_constraints: | ||
| # allow trailing commas for robustness (even though it may not be | ||
| # standard-compliant it seems to occur in some packages) | ||
| constraints = constraints.rstrip(",").rstrip() | ||
| 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.constraints.version.version_union import VersionUnion | ||
|
|
||
| return VersionUnion.of(*or_groups) | ||
|
|
||
|
|
||
| def parse_single_constraint(constraint: str) -> VersionConstraint: | ||
| from poetry.core.constraints.version.patterns import BASIC_CONSTRAINT | ||
| from poetry.core.constraints.version.patterns import CARET_CONSTRAINT | ||
| from poetry.core.constraints.version.patterns import TILDE_CONSTRAINT | ||
| from poetry.core.constraints.version.patterns import TILDE_PEP440_CONSTRAINT | ||
| from poetry.core.constraints.version.patterns import X_CONSTRAINT | ||
| from poetry.core.constraints.version.version import Version | ||
| from poetry.core.constraints.version.version_range import VersionRange | ||
| from poetry.core.constraints.version.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.constraints.version.exceptions import ParseConstraintError | ||
|
|
||
| raise ParseConstraintError(f"Could not parse version constraint: {constraint}") |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.