From d89585c31b28caece46534688984dc3dd422559b Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Tue, 16 Mar 2021 01:11:40 +0000 Subject: [PATCH 1/2] Fix the "safe_name" attribute of PackageFile for backwards compatibility Commit 0bd26af11b8f97ca97ccb9859693d7a14acf15c3 introduced a regression that was causing some namespace packages with dots in them fail to upload to PyPI. The reason is because `packaging.utils.canonicalize_name()` is not equivalent to `pkg_resources.safe_name()` as the former transforms the "." into "-", while the later only does it for non-alphanumeric/. characters. Closes: #743 --- changelog/745.bugfix.rst | 1 + tests/test_package.py | 24 ++++++++++++++++++++++++ twine/package.py | 12 ++++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 changelog/745.bugfix.rst diff --git a/changelog/745.bugfix.rst b/changelog/745.bugfix.rst new file mode 100644 index 00000000..a06ed28c --- /dev/null +++ b/changelog/745.bugfix.rst @@ -0,0 +1 @@ +Fixed a regression that was causing some namespace packages with dots in them fail to upload to PyPI. diff --git a/tests/test_package.py b/tests/test_package.py index c6de1976..467e8758 100644 --- a/tests/test_package.py +++ b/tests/test_package.py @@ -11,6 +11,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import string + import pretend import pytest @@ -110,6 +112,28 @@ def test_package_signed_name_is_correct(): assert package.signed_filename == (filename + ".asc") +@pytest.mark.parametrize( + "pkg_name,expected_name", + [ + (string.ascii_letters, string.ascii_letters), + (string.digits, string.digits), + (string.punctuation, "-.-"), + ("mosaik.SimConfig", "mosaik.SimConfig"), + ("mosaik$$$$.SimConfig", "mosaik-.SimConfig"), + ], +) +def test_package_safe_name_is_correct(pkg_name, expected_name): + package = package_file.PackageFile( + filename="tests/fixtures/deprecated-pypirc", + comment=None, + metadata=pretend.stub(name=pkg_name), + python_version=None, + filetype=None, + ) + + assert package.safe_name == expected_name + + @pytest.mark.parametrize("gpg_signature", [(None), (pretend.stub())]) def test_metadata_dictionary(gpg_signature): meta = pretend.stub( diff --git a/twine/package.py b/twine/package.py index 0b68bc9c..e5d424c8 100644 --- a/twine/package.py +++ b/twine/package.py @@ -14,11 +14,11 @@ import hashlib import io import os +import re import subprocess from typing import Dict, NamedTuple, Optional, Sequence, Tuple, Union import importlib_metadata -import packaging.utils import pkginfo from twine import exceptions @@ -44,6 +44,14 @@ MetadataValue = Union[str, Sequence[str]] +def _safe_name(name: str) -> str: + """Convert an arbitrary string to a standard distribution name. + + Any runs of non-alphanumeric/. characters are replaced with a single '-'. + """ + return re.sub("[^A-Za-z0-9.]+", "-", name) + + class PackageFile: def __init__( self, @@ -59,7 +67,7 @@ def __init__( self.metadata = metadata self.python_version = python_version self.filetype = filetype - self.safe_name = packaging.utils.canonicalize_name(metadata.name) + self.safe_name = _safe_name(metadata.name) self.signed_filename = self.filename + ".asc" self.signed_basefilename = self.basefilename + ".asc" self.gpg_signature: Optional[Tuple[str, bytes]] = None From 421ae7c909d69fa0b5f7b53701dd7b3a91dfca8b Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Tue, 16 Mar 2021 11:14:33 +0000 Subject: [PATCH 2/2] Update docstring of safe_name() Co-authored-by: Brian Rutledge --- twine/package.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/twine/package.py b/twine/package.py index e5d424c8..745752ff 100644 --- a/twine/package.py +++ b/twine/package.py @@ -48,6 +48,9 @@ def _safe_name(name: str) -> str: """Convert an arbitrary string to a standard distribution name. Any runs of non-alphanumeric/. characters are replaced with a single '-'. + + Copied from pkg_resources.safe_name for compatibility with warehouse. + See https://github.com/pypa/twine/issues/743. """ return re.sub("[^A-Za-z0-9.]+", "-", name)