From 44ddd49c25bd19b1f1d3824a5faa745a0b0e31d8 Mon Sep 17 00:00:00 2001 From: David Hotham Date: Sun, 11 Sep 2022 17:16:50 +0100 Subject: [PATCH 1/3] Don't normalize or escape versions --- src/poetry/core/masonry/builders/sdist.py | 2 +- src/poetry/core/masonry/builders/wheel.py | 6 +- src/poetry/core/masonry/metadata.py | 3 +- src/poetry/core/masonry/utils/helpers.py | 9 --- src/poetry/core/utils/helpers.py | 6 -- tests/masonry/utils/test_helpers.py | 18 ------ tests/semver/test_version.py | 70 ++++++++++++++++++++++ tests/utils/test_helpers.py | 71 ----------------------- 8 files changed, 74 insertions(+), 111 deletions(-) diff --git a/src/poetry/core/masonry/builders/sdist.py b/src/poetry/core/masonry/builders/sdist.py index 7aa1e3313..d2809b5e9 100644 --- a/src/poetry/core/masonry/builders/sdist.py +++ b/src/poetry/core/masonry/builders/sdist.py @@ -204,7 +204,7 @@ def build_setup(self) -> bytes: return SETUP.format( before="\n".join(before), name=str(self._meta.name), - version=str(self._meta.version), + version=self._meta.version, description=str(self._meta.summary), long_description=str(self._meta.description), author=str(self._meta.author), diff --git a/src/poetry/core/masonry/builders/wheel.py b/src/poetry/core/masonry/builders/wheel.py index 01533e7b6..705f7f1ed 100644 --- a/src/poetry/core/masonry/builders/wheel.py +++ b/src/poetry/core/masonry/builders/wheel.py @@ -24,7 +24,6 @@ from poetry.core.masonry.builders.builder import Builder from poetry.core.masonry.builders.sdist import SdistBuilder from poetry.core.masonry.utils.helpers import escape_name -from poetry.core.masonry.utils.helpers import escape_version from poetry.core.masonry.utils.helpers import normalize_file_permissions from poetry.core.masonry.utils.package_include import PackageInclude from poetry.core.semver.helpers import parse_constraint @@ -282,7 +281,7 @@ def wheel_data_folder(self) -> str: @property def wheel_filename(self) -> str: name = escape_name(self._package.pretty_name) - version = escape_version(self._meta.version) + version = self._meta.version return f"{name}-{version}-{self.tag}.whl" def supports_python2(self) -> bool: @@ -292,9 +291,8 @@ def supports_python2(self) -> bool: def dist_info_name(self, distribution: str, version: str) -> str: escaped_name = escape_name(distribution) - escaped_version = escape_version(version) - return f"{escaped_name}-{escaped_version}.dist-info" + return f"{escaped_name}-{version}.dist-info" @property def tag(self) -> str: diff --git a/src/poetry/core/masonry/metadata.py b/src/poetry/core/masonry/metadata.py index 33c76d2e3..1ef34c2c5 100644 --- a/src/poetry/core/masonry/metadata.py +++ b/src/poetry/core/masonry/metadata.py @@ -49,13 +49,12 @@ class Metadata: def from_package(cls, package: Package) -> Metadata: from packaging.utils import canonicalize_name - from poetry.core.utils.helpers import normalize_version from poetry.core.version.helpers import format_python_constraint meta = cls() meta.name = canonicalize_name(package.name) - meta.version = normalize_version(package.version.text) + meta.version = package.version.to_string() meta.summary = package.description if package.readmes: descriptions = [] diff --git a/src/poetry/core/masonry/utils/helpers.py b/src/poetry/core/masonry/utils/helpers.py index b79089f3e..5f9631904 100644 --- a/src/poetry/core/masonry/utils/helpers.py +++ b/src/poetry/core/masonry/utils/helpers.py @@ -19,15 +19,6 @@ def normalize_file_permissions(st_mode: int) -> int: return new_mode -def escape_version(version: str) -> str: - """ - Escaped version in wheel filename. Doesn't exactly follow - the escaping specification in :pep:`427#escaping-and-unicode` - because this conflicts with :pep:`440#local-version-identifiers`. - """ - return re.sub(r"[^\w\d.+]+", "_", version, flags=re.UNICODE) - - def escape_name(name: str) -> str: """ Escaped wheel name as specified in https://packaging.python.org/en/latest/specifications/binary-distribution-format/#escaping-and-unicode. diff --git a/src/poetry/core/utils/helpers.py b/src/poetry/core/utils/helpers.py index 3e03d0c28..acd5f36d1 100644 --- a/src/poetry/core/utils/helpers.py +++ b/src/poetry/core/utils/helpers.py @@ -13,8 +13,6 @@ from packaging.utils import canonicalize_name -from poetry.core.version.pep440 import PEP440Version - def combine_unicode(string: str) -> str: return unicodedata.normalize("NFC", string) @@ -24,10 +22,6 @@ def module_name(name: str) -> str: return canonicalize_name(name).replace("-", "_") -def normalize_version(version: str) -> str: - return PEP440Version.parse(version).to_string() - - @contextmanager def temporary_directory(*args: Any, **kwargs: Any) -> Iterator[str]: name = tempfile.mkdtemp(*args, **kwargs) diff --git a/tests/masonry/utils/test_helpers.py b/tests/masonry/utils/test_helpers.py index 8be13c40a..8bc636271 100644 --- a/tests/masonry/utils/test_helpers.py +++ b/tests/masonry/utils/test_helpers.py @@ -3,24 +3,6 @@ import pytest from poetry.core.masonry.utils.helpers import escape_name -from poetry.core.masonry.utils.helpers import escape_version - - -@pytest.mark.parametrize( - "version,expected", - [ - ("1.2.3", "1.2.3"), - ("1.2.3_1", "1.2.3_1"), - ("1.2.3-1", "1.2.3_1"), - ("1.2.3-1", "1.2.3_1"), - ("2022.2", "2022.2"), - ("12.20.12-----451---14-1-4-41", "12.20.12_451_14_1_4_41"), - ("1.0b2.dev1", "1.0b2.dev1"), - ("1.0+abc.7", "1.0+abc.7"), - ], -) -def test_escape_version(version: str, expected: str) -> None: - assert escape_version(version) == expected @pytest.mark.parametrize( diff --git a/tests/semver/test_version.py b/tests/semver/test_version.py index 99231c958..31a8bffdb 100644 --- a/tests/semver/test_version.py +++ b/tests/semver/test_version.py @@ -288,3 +288,73 @@ def test_difference() -> None: assert ( v.difference(VersionRange(Version.parse("1.4.0"), Version.parse("3.0.0"))) == v ) + + +@pytest.mark.parametrize( + "version,normalized_version", + [ + ( # already normalized version + "1!2.3.4.5.6a7.post8.dev9+local1.123.abc", + "1!2.3.4.5.6a7.post8.dev9+local1.123.abc", + ), + # PEP 440 Normalization + # Case sensitivity + ("1.1RC1", "1.1rc1"), + # Integer Normalization + ("00", "0"), + ("09000", "9000"), + ("1.0+foo0100", "1.0+foo0100"), + # Pre-release separators + ("1.1.a1", "1.1a1"), + ("1.1-a1", "1.1a1"), + ("1.1_a1", "1.1a1"), + ("1.1a.1", "1.1a1"), + ("1.1a-1", "1.1a1"), + ("1.1a_1", "1.1a1"), + # Pre-release spelling + ("1.1alpha1", "1.1a1"), + ("1.1beta2", "1.1b2"), + ("1.1c3", "1.1rc3"), + ("1.1pre4", "1.1rc4"), + ("1.1preview5", "1.1rc5"), + # Implicit pre-release number + ("1.2a", "1.2a0"), + # Post release separators + ("1.2.post2", "1.2.post2"), + ("1.2-post2", "1.2.post2"), + ("1.2_post2", "1.2.post2"), + ("1.2post.2", "1.2.post2"), + ("1.2post-2", "1.2.post2"), + ("1.2post_2", "1.2.post2"), + # Post release spelling + ("1.0-r4", "1.0.post4"), + ("1.0-rev4", "1.0.post4"), + # Implicit post release number + ("1.2.post", "1.2.post0"), + # Implicit post releases + ("1.0-1", "1.0.post1"), + # Development release separators + ("1.2.dev2", "1.2.dev2"), + ("1.2-dev2", "1.2.dev2"), + ("1.2_dev2", "1.2.dev2"), + ("1.2dev.2", "1.2.dev2"), + ("1.2dev-2", "1.2.dev2"), + ("1.2dev_2", "1.2.dev2"), + # Implicit development release number + ("1.2.dev", "1.2.dev0"), + # Local version segments + ("1.0+ubuntu-1", "1.0+ubuntu.1"), + ("1.0+ubuntu_1", "1.0+ubuntu.1"), + # Preceding v character + ("v1.0", "1.0"), + # Leading and Trailing Whitespace + (" 1.0 ", "1.0"), + ("\t1.0\t", "1.0"), + ("\n1.0\n", "1.0"), + ("\r\n1.0\r\n", "1.0"), + ("\f1.0\f", "1.0"), + ("\v1.0\v", "1.0"), + ], +) +def test_to_string_normalizes(version: str, normalized_version: str) -> None: + assert Version.parse(version).to_string() == normalized_version diff --git a/tests/utils/test_helpers.py b/tests/utils/test_helpers.py index 2bb862add..f8fe4393c 100644 --- a/tests/utils/test_helpers.py +++ b/tests/utils/test_helpers.py @@ -8,82 +8,11 @@ import pytest from poetry.core.utils.helpers import combine_unicode -from poetry.core.utils.helpers import normalize_version from poetry.core.utils.helpers import parse_requires from poetry.core.utils.helpers import readme_content_type from poetry.core.utils.helpers import temporary_directory -@pytest.mark.parametrize( - "version,normalized_version", - [ - ( # already normalized version - "1!2.3.4.5.6a7.post8.dev9+local1.123.abc", - "1!2.3.4.5.6a7.post8.dev9+local1.123.abc", - ), - # PEP 440 Normalization - # Case sensitivity - ("1.1RC1", "1.1rc1"), - # Integer Normalization - ("00", "0"), - ("09000", "9000"), - ("1.0+foo0100", "1.0+foo0100"), - # Pre-release separators - ("1.1.a1", "1.1a1"), - ("1.1-a1", "1.1a1"), - ("1.1_a1", "1.1a1"), - ("1.1a.1", "1.1a1"), - ("1.1a-1", "1.1a1"), - ("1.1a_1", "1.1a1"), - # Pre-release spelling - ("1.1alpha1", "1.1a1"), - ("1.1beta2", "1.1b2"), - ("1.1c3", "1.1rc3"), - ("1.1pre4", "1.1rc4"), - ("1.1preview5", "1.1rc5"), - # Implicit pre-release number - ("1.2a", "1.2a0"), - # Post release separators - ("1.2.post2", "1.2.post2"), - ("1.2-post2", "1.2.post2"), - ("1.2_post2", "1.2.post2"), - ("1.2post.2", "1.2.post2"), - ("1.2post-2", "1.2.post2"), - ("1.2post_2", "1.2.post2"), - # Post release spelling - ("1.0-r4", "1.0.post4"), - ("1.0-rev4", "1.0.post4"), - # Implicit post release number - ("1.2.post", "1.2.post0"), - # Implicit post releases - ("1.0-1", "1.0.post1"), - # Development release separators - ("1.2.dev2", "1.2.dev2"), - ("1.2-dev2", "1.2.dev2"), - ("1.2_dev2", "1.2.dev2"), - ("1.2dev.2", "1.2.dev2"), - ("1.2dev-2", "1.2.dev2"), - ("1.2dev_2", "1.2.dev2"), - # Implicit development release number - ("1.2.dev", "1.2.dev0"), - # Local version segments - ("1.0+ubuntu-1", "1.0+ubuntu.1"), - ("1.0+ubuntu_1", "1.0+ubuntu.1"), - # Preceding v character - ("v1.0", "1.0"), - # Leading and Trailing Whitespace - (" 1.0 ", "1.0"), - ("\t1.0\t", "1.0"), - ("\n1.0\n", "1.0"), - ("\r\n1.0\r\n", "1.0"), - ("\f1.0\f", "1.0"), - ("\v1.0\v", "1.0"), - ], -) -def test_normalize_version(version: str, normalized_version: str) -> None: - assert normalize_version(version) == normalized_version - - def test_parse_requires() -> None: requires = """\ jsonschema>=2.6.0.0,<3.0.0.0 From db8713862c09f158ea122764fbd2aca56bb66030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20D=C3=B6ring?= <30527984+radoering@users.noreply.github.com> Date: Sat, 17 Sep 2022 19:50:12 +0200 Subject: [PATCH 2/3] deprecate unused methods instead of removing them --- src/poetry/core/masonry/utils/helpers.py | 15 +++++++++++++++ src/poetry/core/utils/helpers.py | 12 ++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/poetry/core/masonry/utils/helpers.py b/src/poetry/core/masonry/utils/helpers.py index 5f9631904..7a3738c6a 100644 --- a/src/poetry/core/masonry/utils/helpers.py +++ b/src/poetry/core/masonry/utils/helpers.py @@ -1,6 +1,7 @@ from __future__ import annotations import re +import warnings def normalize_file_permissions(st_mode: int) -> int: @@ -19,6 +20,20 @@ def normalize_file_permissions(st_mode: int) -> int: return new_mode +def escape_version(version: str) -> str: + """ + Escaped version in wheel filename. Doesn't exactly follow + the escaping specification in :pep:`427#escaping-and-unicode` + because this conflicts with :pep:`440#local-version-identifiers`. + """ + warnings.warn( + "escape_version() is deprecated. Use Version.parse().to_string() instead.", + DeprecationWarning, + stacklevel=2, + ) + return re.sub(r"[^\w\d.+]+", "_", version, flags=re.UNICODE) + + def escape_name(name: str) -> str: """ Escaped wheel name as specified in https://packaging.python.org/en/latest/specifications/binary-distribution-format/#escaping-and-unicode. diff --git a/src/poetry/core/utils/helpers.py b/src/poetry/core/utils/helpers.py index acd5f36d1..dd41b2459 100644 --- a/src/poetry/core/utils/helpers.py +++ b/src/poetry/core/utils/helpers.py @@ -5,6 +5,7 @@ import stat import tempfile import unicodedata +import warnings from contextlib import contextmanager from pathlib import Path @@ -13,6 +14,8 @@ from packaging.utils import canonicalize_name +from poetry.core.version.pep440 import PEP440Version + def combine_unicode(string: str) -> str: return unicodedata.normalize("NFC", string) @@ -22,6 +25,15 @@ def module_name(name: str) -> str: return canonicalize_name(name).replace("-", "_") +def normalize_version(version: str) -> str: + warnings.warn( + "normalize_version() is deprecated. Use Version.parse().to_string() instead.", + DeprecationWarning, + stacklevel=2, + ) + return PEP440Version.parse(version).to_string() + + @contextmanager def temporary_directory(*args: Any, **kwargs: Any) -> Iterator[str]: name = tempfile.mkdtemp(*args, **kwargs) From 86a49d9c5cf464870ba4222f1d85e2e723aefa1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20D=C3=B6ring?= <30527984+radoering@users.noreply.github.com> Date: Sat, 17 Sep 2022 19:50:53 +0200 Subject: [PATCH 3/3] add missing test --- tests/masonry/builders/fixtures/epoch/README.rst | 2 ++ tests/masonry/builders/fixtures/epoch/epoch.py | 3 +++ tests/masonry/builders/fixtures/epoch/pyproject.toml | 12 ++++++++++++ tests/masonry/builders/test_wheel.py | 12 ++++++++++++ 4 files changed, 29 insertions(+) create mode 100644 tests/masonry/builders/fixtures/epoch/README.rst create mode 100644 tests/masonry/builders/fixtures/epoch/epoch.py create mode 100644 tests/masonry/builders/fixtures/epoch/pyproject.toml diff --git a/tests/masonry/builders/fixtures/epoch/README.rst b/tests/masonry/builders/fixtures/epoch/README.rst new file mode 100644 index 000000000..ce1f88eca --- /dev/null +++ b/tests/masonry/builders/fixtures/epoch/README.rst @@ -0,0 +1,2 @@ +Epoch +===== diff --git a/tests/masonry/builders/fixtures/epoch/epoch.py b/tests/masonry/builders/fixtures/epoch/epoch.py new file mode 100644 index 000000000..8de3a59b0 --- /dev/null +++ b/tests/masonry/builders/fixtures/epoch/epoch.py @@ -0,0 +1,3 @@ +"""Example module""" + +__version__ = "1!2.0" diff --git a/tests/masonry/builders/fixtures/epoch/pyproject.toml b/tests/masonry/builders/fixtures/epoch/pyproject.toml new file mode 100644 index 000000000..87c34f31d --- /dev/null +++ b/tests/masonry/builders/fixtures/epoch/pyproject.toml @@ -0,0 +1,12 @@ +[tool.poetry] +name = "epoch" +version = "1!2.0" +description = "Some description." +authors = [ + "Sébastien Eustace " +] +license = "MIT" + +readme = "README.rst" + +homepage = "https://python-poetry.org/" diff --git a/tests/masonry/builders/test_wheel.py b/tests/masonry/builders/test_wheel.py index bde27857b..7efa24166 100644 --- a/tests/masonry/builders/test_wheel.py +++ b/tests/masonry/builders/test_wheel.py @@ -72,6 +72,18 @@ def test_wheel_prerelease() -> None: assert whl.exists() +def test_wheel_epoch() -> None: + module_path = fixtures_dir / "epoch" + WheelBuilder.make(Factory().create_poetry(module_path)) + + whl = module_path / "dist" / "epoch-1!2.0-py2.py3-none-any.whl" + + assert whl.exists() + + with zipfile.ZipFile(str(whl)) as z: + assert "epoch-1!2.0.dist-info/METADATA" in z.namelist() + + def test_wheel_excluded_data() -> None: module_path = fixtures_dir / "default_with_excluded_data_toml" WheelBuilder.make(Factory().create_poetry(module_path))