Skip to content

Commit

Permalink
Merge pull request #4766 from di/fix/3777
Browse files Browse the repository at this point in the history
Fix "Wheel naming is not following PEP 491 convention"
  • Loading branch information
jaraco authored Feb 2, 2025
2 parents a443f76 + 8ba79d9 commit 75f7782
Show file tree
Hide file tree
Showing 7 changed files with 25 additions and 24 deletions.
1 change: 1 addition & 0 deletions newsfragments/4766.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix wheel file naming to follow binary distribution specification -- by :user:`di`
8 changes: 7 additions & 1 deletion setuptools/_normalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,13 @@ def filename_component_broken(value: str) -> str:
def safer_name(value: str) -> str:
"""Like ``safe_name`` but can be used as filename component for wheel"""
# See bdist_wheel.safer_name
return filename_component(safe_name(value))
return (
# Per https://packaging.python.org/en/latest/specifications/name-normalization/#name-normalization
re.sub(r"[-_.]+", "-", safe_name(value))
.lower()
# Per https://packaging.python.org/en/latest/specifications/binary-distribution-format/#escaping-and-unicode
.replace("-", "_")
)


def safer_best_effort_version(value: str) -> str:
Expand Down
12 changes: 1 addition & 11 deletions setuptools/command/bdist_wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,13 @@
from wheel.wheelfile import WheelFile

from .. import Command, __version__, _shutil
from .._normalization import safer_name
from ..warnings import SetuptoolsDeprecationWarning
from .egg_info import egg_info as egg_info_cls

from distutils import log


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)


def safe_version(version: str) -> str:
"""
Convert an arbitrary string to a standard version string
Expand Down Expand Up @@ -133,10 +127,6 @@ def get_abi_tag() -> str | None:
return abi


def safer_name(name: str) -> str:
return safe_name(name).replace("-", "_")


def safer_version(version: str) -> str:
return safe_version(version).replace("-", "_")

Expand Down
4 changes: 2 additions & 2 deletions setuptools/tests/test_bdist_wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,9 @@ def test_no_scripts(wheel_paths):


def test_unicode_record(wheel_paths):
path = next(path for path in wheel_paths if "unicode.dist" in path)
path = next(path for path in wheel_paths if "unicode_dist" in path)
with ZipFile(path) as zf:
record = zf.read("unicode.dist-0.1.dist-info/RECORD")
record = zf.read("unicode_dist-0.1.dist-info/RECORD")

assert "åäö_日本語.py".encode() in record

Expand Down
4 changes: 2 additions & 2 deletions setuptools/tests/test_dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from setuptools import Distribution
from setuptools.dist import check_package_data, check_specifier

from .test_easy_install import make_nspkg_sdist
from .test_easy_install import make_trivial_sdist
from .test_find_packages import ensure_files
from .textwrap import DALS

Expand All @@ -25,7 +25,7 @@ def test_dist_fetch_build_egg(tmpdir):
def sdist_with_index(distname, version):
dist_dir = index.mkdir(distname)
dist_sdist = f'{distname}-{version}.tar.gz'
make_nspkg_sdist(str(dist_dir.join(dist_sdist)), distname, version)
make_trivial_sdist(str(dist_dir.join(dist_sdist)), distname, version)
with dist_dir.join('index.html').open('w') as fp:
fp.write(
DALS(
Expand Down
2 changes: 1 addition & 1 deletion setuptools/tests/test_dist_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def test_dist_info_is_the_same_as_in_wheel(
dist_info = next(tmp_path.glob("dir_dist/*.dist-info"))

assert dist_info.name == wheel_dist_info.name
assert dist_info.name.startswith(f"{name.replace('-', '_')}-{version}{suffix}")
assert dist_info.name.startswith(f"my_proj-{version}{suffix}")
for file in "METADATA", "entry_points.txt":
assert read(dist_info / file) == read(wheel_dist_info / file)

Expand Down
18 changes: 11 additions & 7 deletions setuptools/tests/test_easy_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import setuptools.command.easy_install as ei
from pkg_resources import Distribution as PRDistribution, normalize_path, working_set
from setuptools import sandbox
from setuptools._normalization import safer_name
from setuptools.command.easy_install import PthDistributions
from setuptools.dist import Distribution
from setuptools.sandbox import run_setup
Expand Down Expand Up @@ -670,11 +671,11 @@ def test_setup_requires_override_nspkg(self, use_setup_cfg):

with contexts.save_pkg_resources_state():
with contexts.tempdir() as temp_dir:
foobar_1_archive = os.path.join(temp_dir, 'foo.bar-0.1.tar.gz')
foobar_1_archive = os.path.join(temp_dir, 'foo_bar-0.1.tar.gz')
make_nspkg_sdist(foobar_1_archive, 'foo.bar', '0.1')
# Now actually go ahead an extract to the temp dir and add the
# extracted path to sys.path so foo.bar v0.1 is importable
foobar_1_dir = os.path.join(temp_dir, 'foo.bar-0.1')
foobar_1_dir = os.path.join(temp_dir, 'foo_bar-0.1')
os.mkdir(foobar_1_dir)
with tarfile.open(foobar_1_archive) as tf:
tf.extraction_filter = lambda member, path: member
Expand All @@ -697,7 +698,7 @@ def test_setup_requires_override_nspkg(self, use_setup_cfg):
len(foo.__path__) == 2):
print('FAIL')
if 'foo.bar-0.2' not in foo.__path__[0]:
if 'foo_bar-0.2' not in foo.__path__[0]:
print('FAIL')
"""
)
Expand All @@ -718,8 +719,8 @@ def test_setup_requires_override_nspkg(self, use_setup_cfg):
# Don't even need to install the package, just
# running the setup.py at all is sufficient
run_setup(test_setup_py, ['--name'])
except pkg_resources.VersionConflict:
self.fail(
except pkg_resources.VersionConflict: # pragma: nocover
pytest.fail(
'Installing setup.py requirements caused a VersionConflict'
)

Expand Down Expand Up @@ -1120,6 +1121,8 @@ def make_nspkg_sdist(dist_path, distname, version):
package with the same name as distname. The top-level package is
designated a namespace package).
"""
# Assert that the distname contains at least one period
assert '.' in distname

parts = distname.split('.')
nspackage = parts[0]
Expand Down Expand Up @@ -1207,10 +1210,11 @@ def create_setup_requires_package(
package itself is just 'test_pkg'.
"""

normalized_distname = safer_name(distname)
test_setup_attrs = {
'name': 'test_pkg',
'version': '0.0',
'setup_requires': [f'{distname}=={version}'],
'setup_requires': [f'{normalized_distname}=={version}'],
'dependency_links': [os.path.abspath(path)],
}
if setup_attrs:
Expand Down Expand Up @@ -1259,7 +1263,7 @@ def create_setup_requires_package(
with open(os.path.join(test_pkg, 'setup.py'), 'w', encoding="utf-8") as f:
f.write(setup_py_template % test_setup_attrs)

foobar_path = os.path.join(path, f'{distname}-{version}.tar.gz')
foobar_path = os.path.join(path, f'{normalized_distname}-{version}.tar.gz')
make_package(foobar_path, distname, version)

return test_pkg
Expand Down

0 comments on commit 75f7782

Please sign in to comment.