Skip to content

Commit

Permalink
version: always return normalized version according to PEP440 when ca…
Browse files Browse the repository at this point in the history
…lling to_string
  • Loading branch information
radoering committed May 10, 2022
1 parent 9c1edb3 commit 7d70b01
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 89 deletions.
2 changes: 1 addition & 1 deletion src/poetry/core/utils/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def module_name(name: str) -> str:


def normalize_version(version: str) -> str:
return PEP440Version.parse(version).normalize()
return PEP440Version.parse(version).to_string()


@contextmanager
Expand Down
82 changes: 35 additions & 47 deletions src/poetry/core/version/pep440/segments.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,23 @@
from typing import Union


RELEASE_PHASE_ALPHA = "alpha"
RELEASE_PHASE_BETA = "beta"
RELEASE_PHASE_RC = "rc"
RELEASE_PHASE_PREVIEW = "preview"
RELEASE_PHASE_POST = "post"
RELEASE_PHASE_REV = "rev"
RELEASE_PHASE_DEV = "dev"
RELEASE_PHASES = {
RELEASE_PHASE_ALPHA: "a",
RELEASE_PHASE_BETA: "b",
RELEASE_PHASE_RC: "c",
RELEASE_PHASE_PREVIEW: "pre",
RELEASE_PHASE_POST: "-", # shorthand of 1.2.3-post1 is 1.2.3-1
RELEASE_PHASE_REV: "r",
RELEASE_PHASE_DEV: "dev",
# Release phase IDs according to PEP440
RELEASE_PHASE_ID_ALPHA = "a"
RELEASE_PHASE_ID_BETA = "b"
RELEASE_PHASE_ID_RC = "rc"
RELEASE_PHASE_ID_POST = "post"
RELEASE_PHASE_ID_DEV = "dev"

RELEASE_PHASE_SPELLINGS = {
RELEASE_PHASE_ID_ALPHA: {RELEASE_PHASE_ID_ALPHA, "alpha"},
RELEASE_PHASE_ID_BETA: {RELEASE_PHASE_ID_BETA, "beta"},
RELEASE_PHASE_ID_RC: {RELEASE_PHASE_ID_RC, "c", "pre", "preview"},
RELEASE_PHASE_ID_POST: {RELEASE_PHASE_ID_POST, "r", "rev", "-"},
RELEASE_PHASE_ID_DEV: {RELEASE_PHASE_ID_DEV},
}
RELEASE_PHASES_NORMALIZED = {
RELEASE_PHASE_ALPHA: "a",
RELEASE_PHASE_BETA: "b",
RELEASE_PHASE_RC: "rc",
RELEASE_PHASE_PREVIEW: "rc",
RELEASE_PHASE_POST: "post",
RELEASE_PHASE_REV: "post",
RELEASE_PHASE_DEV: "dev",
RELEASE_PHASE_NORMALIZATIONS = {
s: id_ for id_, spellings in RELEASE_PHASE_SPELLINGS.items() for s in spellings
}
RELEASE_PHASES_SHORT = {v: k for k, v in RELEASE_PHASES.items() if k != "post"}


@dataclasses.dataclass(frozen=True, eq=True, order=True)
Expand Down Expand Up @@ -118,41 +109,38 @@ class ReleaseTag:
number: int = dataclasses.field(default=0)

def __post_init__(self) -> None:
object.__setattr__(self, "phase", self.expand(self.phase))

def normalize(self) -> str:
normalized_phase = RELEASE_PHASES_NORMALIZED.get(self.phase, self.phase)
return f"{normalized_phase}{self.number}"

@classmethod
def shorten(cls, phase: str) -> str:
return RELEASE_PHASES.get(phase, phase)

@classmethod
def expand(cls, phase: str) -> str:
return RELEASE_PHASES_SHORT.get(phase, phase)
object.__setattr__(
self, "phase", RELEASE_PHASE_NORMALIZATIONS.get(self.phase, self.phase)
)

def to_string(self, short: bool = False) -> str:
if short:
return f"{self.shorten(self.phase)}{self.number}"
return f"{self.phase}.{self.number}"
import warnings

warnings.warn(
"Parameter 'short' has no effect and will be removed. "
"(Release tags are always normalized according to PEP 440 now.)",
DeprecationWarning,
stacklevel=2,
)

return f"{self.phase}{self.number}"

def next(self) -> ReleaseTag:
return dataclasses.replace(self, phase=self.phase, number=self.number + 1)

def next_phase(self) -> ReleaseTag | None:
if self.phase in [
RELEASE_PHASE_POST,
RELEASE_PHASE_RC,
RELEASE_PHASE_REV,
RELEASE_PHASE_DEV,
RELEASE_PHASE_ID_POST,
RELEASE_PHASE_ID_RC,
RELEASE_PHASE_ID_DEV,
]:
return None

if self.phase == RELEASE_PHASE_ALPHA:
_phase = RELEASE_PHASE_BETA
elif self.phase == RELEASE_PHASE_BETA:
_phase = RELEASE_PHASE_RC
if self.phase == RELEASE_PHASE_ID_ALPHA:
_phase = RELEASE_PHASE_ID_BETA
elif self.phase == RELEASE_PHASE_ID_BETA:
_phase = RELEASE_PHASE_ID_RC
else:
return None

Expand Down
58 changes: 23 additions & 35 deletions src/poetry/core/version/pep440/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
from typing import Any
from typing import TypeVar

from poetry.core.version.pep440.segments import RELEASE_PHASE_ALPHA
from poetry.core.version.pep440.segments import RELEASE_PHASE_DEV
from poetry.core.version.pep440.segments import RELEASE_PHASE_POST
from poetry.core.version.pep440.segments import RELEASE_PHASE_ID_ALPHA
from poetry.core.version.pep440.segments import RELEASE_PHASE_ID_DEV
from poetry.core.version.pep440.segments import RELEASE_PHASE_ID_POST
from poetry.core.version.pep440.segments import Release
from poetry.core.version.pep440.segments import ReleaseTag

Expand Down Expand Up @@ -142,52 +142,38 @@ def non_semver_parts(self) -> tuple[int, ...]:
assert isinstance(self.release.extra, tuple)
return self.release.extra

def normalize(self) -> str:
def to_string(self, short: bool = False) -> str:
if short:
import warnings

warnings.warn(
"Parameter 'short' has no effect and will be removed. "
"(Versions are always normalized according to PEP 440 now.)",
DeprecationWarning,
stacklevel=2,
)

version_string = self.release.to_string()

if self.epoch:
# if epoch is non-zero we should include it
version_string = f"{self.epoch}!{version_string}"

if self.pre:
version_string += self.pre.normalize()
version_string += self.pre.to_string()

if self.post:
version_string = f"{version_string}.{self.post.normalize()}"
version_string = f"{version_string}.{self.post.to_string()}"

if self.dev:
version_string = f"{version_string}.{self.dev.normalize()}"
version_string = f"{version_string}.{self.dev.to_string()}"

if self.local:
assert isinstance(self.local, tuple)
version_string += "+" + ".".join(map(str, self.local))

return version_string.lower()

def to_string(self, short: bool = False) -> str:
dash = "-" if not short else ""

version_string = dash.join(
part
for part in [
self.release.to_string(),
self.pre.to_string(short) if self.pre else None,
self.post.to_string(short) if self.post else None,
self.dev.to_string(short) if self.dev else None,
]
if part
)

if self.epoch:
# if epoch is non-zero we should include it
version_string = f"{self.epoch}!{version_string}"

if self.local:
assert isinstance(self.local, tuple)
version_string += "+" + ".".join(map(str, self.local))

return version_string

@classmethod
def parse(cls: type[T], value: str) -> T:
from poetry.core.version.pep440.parser import parse_pep440
Expand Down Expand Up @@ -241,15 +227,15 @@ def next_prerelease(self: T, next_phase: bool = False) -> PEP440Version:
assert self.pre is not None
pre = self.pre.next_phase() if next_phase else self.pre.next()
else:
pre = ReleaseTag(RELEASE_PHASE_ALPHA)
pre = ReleaseTag(RELEASE_PHASE_ID_ALPHA)
return self.__class__(epoch=self.epoch, release=self.release, pre=pre)

def next_postrelease(self: T) -> T:
if self.is_postrelease():
assert self.post is not None
post = self.post.next()
else:
post = ReleaseTag(RELEASE_PHASE_POST)
post = ReleaseTag(RELEASE_PHASE_ID_POST)
return self.__class__(
epoch=self.epoch,
release=self.release,
Expand All @@ -263,7 +249,7 @@ def next_devrelease(self: T) -> T:
assert self.dev is not None
dev = self.dev.next()
else:
dev = ReleaseTag(RELEASE_PHASE_DEV)
dev = ReleaseTag(RELEASE_PHASE_ID_DEV)
return self.__class__(
epoch=self.epoch,
release=self.release,
Expand All @@ -274,7 +260,9 @@ def next_devrelease(self: T) -> T:

def first_prerelease(self: T) -> T:
return self.__class__(
epoch=self.epoch, release=self.release, pre=ReleaseTag(RELEASE_PHASE_ALPHA)
epoch=self.epoch,
release=self.release,
pre=ReleaseTag(RELEASE_PHASE_ID_ALPHA),
)

def replace(self: T, **kwargs: Any) -> T:
Expand Down
9 changes: 3 additions & 6 deletions tests/version/test_version_pep440.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
from poetry.core.version.pep440 import PEP440Version
from poetry.core.version.pep440 import Release
from poetry.core.version.pep440 import ReleaseTag
from poetry.core.version.pep440.segments import RELEASE_PHASES
from poetry.core.version.pep440.segments import RELEASE_PHASES_SHORT
from poetry.core.version.pep440.segments import RELEASE_PHASE_NORMALIZATIONS


@pytest.mark.parametrize(
Expand Down Expand Up @@ -67,12 +66,10 @@ def test_pep440_release_tag_next_phase(
assert ReleaseTag(*parts).next_phase() == result


@pytest.mark.parametrize(
"phase", list({*RELEASE_PHASES.keys(), *RELEASE_PHASES_SHORT.keys()})
)
@pytest.mark.parametrize("phase", list({*RELEASE_PHASE_NORMALIZATIONS.keys()}))
def test_pep440_release_tag_next(phase: str) -> None:
tag = ReleaseTag(phase=phase).next()
assert tag.phase == ReleaseTag.expand(phase)
assert tag.phase == RELEASE_PHASE_NORMALIZATIONS[phase]
assert tag.number == 1


Expand Down

0 comments on commit 7d70b01

Please sign in to comment.