Skip to content

Commit

Permalink
semver: improve constraint parsing
Browse files Browse the repository at this point in the history
This change replaces the custom regex used with
`packaging.version.VERSION_PATTERN` for consistency with other parts of
the code base. Additionally, this fixes previous issues with parsing
pre-release dev releases etc.
  • Loading branch information
abn committed Apr 30, 2022
1 parent ce38eb4 commit ffb2dd1
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 40 deletions.
6 changes: 3 additions & 3 deletions src/poetry/core/packages/constraints/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ def parse_single_constraint(constraint: str) -> Constraint:
m = BASIC_CONSTRAINT.match(constraint)
if m:
op = m.group(1)
version_string = m.group(2).strip()

if op is None:
op = "=="

version = m.group(2).strip()

return Constraint(version, op)
return Constraint(version_string, op)

raise ValueError(f"Could not parse version constraint: {constraint}")

Expand Down
32 changes: 9 additions & 23 deletions src/poetry/core/semver/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,26 +63,19 @@ def parse_single_constraint(constraint: str) -> VersionConstraint:
# Tilde range
m = TILDE_CONSTRAINT.match(constraint)
if m:
version = Version.parse(m.group(1))
version = Version.parse(m.group("version"))
high = version.stable.next_minor()
if len(m.group(1).split(".")) == 1:
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:
precision = 1
if m.group(3):
precision += 1

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

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

if precision == 2:
version = Version.parse(m.group("version"))
print(version)
if version.release.precision == 2:
high = version.stable.next_major()
else:
high = version.stable.next_minor()
Expand All @@ -92,14 +85,14 @@ def parse_single_constraint(constraint: str) -> VersionConstraint:
# Caret range
m = CARET_CONSTRAINT.match(constraint)
if m:
version = Version.parse(m.group(1))
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(1)
op = m.group("op")
major = int(m.group(2))
minor = m.group(3)

Expand All @@ -124,15 +117,8 @@ def parse_single_constraint(constraint: str) -> VersionConstraint:
# Basic comparator
m = BASIC_CONSTRAINT.match(constraint)
if m:
op = m.group(1)
version_string = m.group(2)

# Technically invalid constraints like `>= 3.*` will appear
# here as `3.`.
# Pip currently supports these and to avoid breaking existing
# users workflows we need to support them as well. To do so,
# we just remove the inconsequential part.
version_string = version_string.rstrip(".")
op = m.group("op")
version_string = m.group("version")

if version_string == "dev":
version_string = "0.0-dev"
Expand Down
34 changes: 20 additions & 14 deletions src/poetry/core/semver/patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,27 @@

import re

from packaging.version import VERSION_PATTERN

MODIFIERS = (
"[._-]?"
r"((?!post)(?:beta|b|c|pre|RC|alpha|a|patch|pl|p|dev)(?:(?:[.-]?\d+)*)?)?"
r"([+-]?([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?"
)

_COMPLETE_VERSION = (
rf"v?(?:\d+!)?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?{MODIFIERS}(?:\+[^\s]+)?"
)
COMPLETE_VERSION = re.compile(VERSION_PATTERN, re.VERBOSE | re.IGNORECASE)

COMPLETE_VERSION = re.compile("(?i)" + _COMPLETE_VERSION)
CARET_CONSTRAINT = re.compile(
rf"^\^(?P<version>{VERSION_PATTERN})$", re.VERBOSE | re.IGNORECASE
)
TILDE_CONSTRAINT = re.compile(
rf"^~(?!=)\s*(?P<version>{VERSION_PATTERN})$", re.VERBOSE | re.IGNORECASE
)
TILDE_PEP440_CONSTRAINT = re.compile(
rf"^~=\s*(?P<version>{VERSION_PATTERN})\s*$", re.VERBOSE | re.IGNORECASE
)
X_CONSTRAINT = re.compile(
r"^(?P<op>!=|==)?\s*v?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.[xX*])+$"
)

CARET_CONSTRAINT = re.compile(rf"(?i)^\^({_COMPLETE_VERSION})$")
TILDE_CONSTRAINT = re.compile(rf"(?i)^~(?!=)\s*({_COMPLETE_VERSION})$")
TILDE_PEP440_CONSTRAINT = re.compile(rf"(?i)^~=\s*({_COMPLETE_VERSION})$")
X_CONSTRAINT = re.compile(r"^(!=|==)?\s*v?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.[xX*])+$")
BASIC_CONSTRAINT = re.compile(rf"(?i)^(<>|!=|>=?|<=?|==?)?\s*({_COMPLETE_VERSION}|dev)")
# note that we also allow technically incorrect version patterns with astrix (eg: 3.5.*)
# as this is supported by pip and appears in metadata within python packages
BASIC_CONSTRAINT = re.compile(
rf"^(?P<op><>|!=|>=?|<=?|==?)?\s*(?P<version>{VERSION_PATTERN}|dev)(\.\*)?\s*$",
re.VERBOSE | re.IGNORECASE,
)
32 changes: 32 additions & 0 deletions tests/semver/test_parse_constraint.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,28 @@
include_min=True,
),
),
(
"^1.0.0a1.dev0",
VersionRange(
min=Version.from_parts(
1, 0, 0, pre=ReleaseTag("a", 1), dev=ReleaseTag("dev", 0)
),
max=Version.from_parts(2, 0, 0),
include_min=True,
),
),
(
"1.0.0a1.dev0",
VersionRange(
min=Version.from_parts(
1, 0, 0, pre=ReleaseTag("a", 1), dev=ReleaseTag("dev", 0)
),
max=Version.from_parts(
1, 0, 0, pre=ReleaseTag("a", 1), dev=ReleaseTag("dev", 0)
),
include_min=True,
),
),
(
"~1.0.0a1",
VersionRange(
Expand All @@ -190,6 +212,16 @@
include_min=True,
),
),
(
"~1.0.0a1.dev0",
VersionRange(
min=Version.from_parts(
1, 0, 0, pre=ReleaseTag("a", 1), dev=ReleaseTag("dev", 0)
),
max=Version.from_parts(1, 1, 0),
include_min=True,
),
),
(
"^0",
VersionRange(
Expand Down
1 change: 1 addition & 0 deletions tests/version/test_requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def assert_requirement(
("name<3.*", {"name": "name", "constraint": "<3.0"}),
("name>3.5.*", {"name": "name", "constraint": ">3.5"}),
("name==1.0.post1", {"name": "name", "constraint": "==1.0.post1"}),
("name==1.2.0b1.dev0", {"name": "name", "constraint": "==1.2.0b1.dev0"}),
(
"name>=1.2.3;python_version=='2.6'",
{
Expand Down

0 comments on commit ffb2dd1

Please sign in to comment.