diff --git a/src/poetry/core/utils/helpers.py b/src/poetry/core/utils/helpers.py index 2b6aacf1f..e538017bc 100644 --- a/src/poetry/core/utils/helpers.py +++ b/src/poetry/core/utils/helpers.py @@ -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 diff --git a/src/poetry/core/version/pep440/segments.py b/src/poetry/core/version/pep440/segments.py index eb5af8b8b..f4292d08e 100644 --- a/src/poetry/core/version/pep440/segments.py +++ b/src/poetry/core/version/pep440/segments.py @@ -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) @@ -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 diff --git a/src/poetry/core/version/pep440/version.py b/src/poetry/core/version/pep440/version.py index 423a08938..c1252a6f4 100644 --- a/src/poetry/core/version/pep440/version.py +++ b/src/poetry/core/version/pep440/version.py @@ -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 @@ -142,7 +142,17 @@ 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: @@ -150,13 +160,13 @@ def normalize(self) -> str: 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) @@ -164,30 +174,6 @@ def normalize(self) -> str: 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 @@ -241,7 +227,7 @@ 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: @@ -249,7 +235,7 @@ def next_postrelease(self: T) -> T: 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, @@ -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, @@ -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: diff --git a/tests/version/test_version_pep440.py b/tests/version/test_version_pep440.py index c3cb9ec03..c816dd02f 100644 --- a/tests/version/test_version_pep440.py +++ b/tests/version/test_version_pep440.py @@ -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( @@ -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