From 8d19c423cd099fccad9b9dfa0403ab9f899015fe Mon Sep 17 00:00:00 2001 From: Philipp A Date: Mon, 1 Mar 2021 15:55:10 +0100 Subject: [PATCH] Normalize dist-info and wheel names According to new rules in https://packaging.python.org/specifications/binary-distribution-format/#escaping-and-unicode Specifically the ones introduced in https://github.com/pypa/packaging.python.org/pull/844 --- flit_core/flit_core/common.py | 19 ++++++++++++++++--- flit_core/flit_core/wheel.py | 7 ++----- .../modulewithlocalversion.py | 5 +++++ .../modulewithlocalversion/pyproject.toml | 10 ++++++++++ tests/test_wheel.py | 11 +++++++++++ 5 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 tests/samples/modulewithlocalversion/modulewithlocalversion.py create mode 100644 tests/samples/modulewithlocalversion/pyproject.toml diff --git a/flit_core/flit_core/common.py b/flit_core/flit_core/common.py index b0505911..120710a4 100644 --- a/flit_core/flit_core/common.py +++ b/flit_core/flit_core/common.py @@ -375,8 +375,21 @@ def metadata_and_module_from_ini_path(ini_path): metadata = make_metadata(module, ini_info) return metadata,module + +def normalize_dist_name(name: str, version: str) -> str: + """Normalizes a name and a PEP 440 version + + The resulting string is valid as dist-info folder name + and as first part of a wheel filename + + See https://packaging.python.org/specifications/binary-distribution-format/#escaping-and-unicode + """ + normalized_name = re.sub(r'[-_.]+', '_', name, flags=re.UNICODE) + assert check_version(version) == version + assert '-' not in version, 'Normalized versions can’t have dashes' + return '{}-{}'.format(normalized_name, version) + + def dist_info_name(distribution, version): """Get the correct name of the .dist-info folder""" - escaped_name = re.sub(r"[^\w\d.]+", "_", distribution, flags=re.UNICODE) - escaped_version = re.sub(r"[^\w\d.]+", "_", version, flags=re.UNICODE) - return u'{}-{}.dist-info'.format(escaped_name, escaped_version) + return normalize_dist_name(distribution, version) + '.dist-info' diff --git a/flit_core/flit_core/wheel.py b/flit_core/flit_core/wheel.py index 2bc55e1f..388a5352 100644 --- a/flit_core/flit_core/wheel.py +++ b/flit_core/flit_core/wheel.py @@ -7,7 +7,6 @@ import logging import os import os.path as osp -import re import stat import sys import tempfile @@ -98,11 +97,9 @@ def dist_info(self): @property def wheel_filename(self): + dist_name = common.normalize_dist_name(self.metadata.name, self.metadata.version) tag = ('py2.' if self.metadata.supports_py2 else '') + 'py3-none-any' - return '{}-{}-{}.whl'.format( - re.sub(r"[^\w\d.]+", "_", self.metadata.name, flags=re.UNICODE), - re.sub(r"[^\w\d.]+", "_", self.metadata.version, flags=re.UNICODE), - tag) + return '{}-{}.whl'.format(dist_name, tag) def _add_file_old(self, full_path, rel_path): log.debug("Adding %s to zip file", full_path) diff --git a/tests/samples/modulewithlocalversion/modulewithlocalversion.py b/tests/samples/modulewithlocalversion/modulewithlocalversion.py new file mode 100644 index 00000000..4d11be92 --- /dev/null +++ b/tests/samples/modulewithlocalversion/modulewithlocalversion.py @@ -0,0 +1,5 @@ +""" +A module with a local version specifier +""" + +__version__ = "0.1.dev0+test" diff --git a/tests/samples/modulewithlocalversion/pyproject.toml b/tests/samples/modulewithlocalversion/pyproject.toml new file mode 100644 index 00000000..bb806691 --- /dev/null +++ b/tests/samples/modulewithlocalversion/pyproject.toml @@ -0,0 +1,10 @@ +[build-system] +requires = ["flit_core >=2,<4"] +build-backend = "flit_core.buildapi" + +[tool.flit.metadata] +module = "modulewithlocalversion" +author = "Sir Robin" +author-email = "robin@camelot.uk" +home-page = "http://github.com/sirrobin/modulewithlocalversion" + diff --git a/tests/test_wheel.py b/tests/test_wheel.py index e863a55d..4cd5c3ed 100644 --- a/tests/test_wheel.py +++ b/tests/test_wheel.py @@ -125,3 +125,14 @@ def test_compression(tmp_path): 'module1-0.1.dist-info/METADATA', ]: assert zf.getinfo(name).compress_type == zipfile.ZIP_DEFLATED + +def test_wheel_module_local_version(copy_sample): + """Test if a local version specifier is preserved in wheel filename and dist-info dir name""" + td = copy_sample('modulewithlocalversion') + make_wheel_in(td / 'pyproject.toml', td) + + whl_file = td / 'modulewithlocalversion-0.1.dev0+test-py2.py3-none-any.whl' + assert_isfile(whl_file) + with unpack(whl_file) as unpacked: + assert_isfile(Path(unpacked, 'modulewithlocalversion.py')) + assert_isdir(Path(unpacked, 'modulewithlocalversion-0.1.dev0+test.dist-info'))