Skip to content

Commit 9559193

Browse files
committed
Merge pull request #4766 from di/fix/3777
Fix "Wheel naming is not following PEP 491 convention"
1 parent d8da7df commit 9559193

File tree

7 files changed

+25
-24
lines changed

7 files changed

+25
-24
lines changed

newsfragments/4766.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix wheel file naming to follow binary distribution specification -- by :user:`di`

setuptools/_normalization.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,13 @@ def filename_component_broken(value: str) -> str:
134134
def safer_name(value: str) -> str:
135135
"""Like ``safe_name`` but can be used as filename component for wheel"""
136136
# See bdist_wheel.safer_name
137-
return filename_component(safe_name(value))
137+
return (
138+
# Per https://packaging.python.org/en/latest/specifications/name-normalization/#name-normalization
139+
re.sub(r"[-_.]+", "-", safe_name(value))
140+
.lower()
141+
# Per https://packaging.python.org/en/latest/specifications/binary-distribution-format/#escaping-and-unicode
142+
.replace("-", "_")
143+
)
138144

139145

140146
def safer_best_effort_version(value: str) -> str:

setuptools/command/bdist_wheel.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from wheel.wheelfile import WheelFile
2727

2828
from .. import Command, __version__
29+
from .._normalization import safer_name
2930
from ..warnings import SetuptoolsDeprecationWarning
3031
from .egg_info import egg_info as egg_info_cls
3132

@@ -35,13 +36,6 @@
3536
from _typeshed import ExcInfo
3637

3738

38-
def safe_name(name: str) -> str:
39-
"""Convert an arbitrary string to a standard distribution name
40-
Any runs of non-alphanumeric/. characters are replaced with a single '-'.
41-
"""
42-
return re.sub("[^A-Za-z0-9.]+", "-", name)
43-
44-
4539
def safe_version(version: str) -> str:
4640
"""
4741
Convert an arbitrary string to a standard version string
@@ -147,10 +141,6 @@ def get_abi_tag() -> str | None:
147141
return abi
148142

149143

150-
def safer_name(name: str) -> str:
151-
return safe_name(name).replace("-", "_")
152-
153-
154144
def safer_version(version: str) -> str:
155145
return safe_version(version).replace("-", "_")
156146

setuptools/tests/test_bdist_wheel.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,9 @@ def test_no_scripts(wheel_paths):
252252

253253

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

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

setuptools/tests/test_dist.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from setuptools import Distribution
99
from setuptools.dist import check_package_data, check_specifier
1010

11-
from .test_easy_install import make_nspkg_sdist
11+
from .test_easy_install import make_trivial_sdist
1212
from .test_find_packages import ensure_files
1313
from .textwrap import DALS
1414

@@ -25,7 +25,7 @@ def test_dist_fetch_build_egg(tmpdir):
2525
def sdist_with_index(distname, version):
2626
dist_dir = index.mkdir(distname)
2727
dist_sdist = '%s-%s.tar.gz' % (distname, version)
28-
make_nspkg_sdist(str(dist_dir.join(dist_sdist)), distname, version)
28+
make_trivial_sdist(str(dist_dir.join(dist_sdist)), distname, version)
2929
with dist_dir.join('index.html').open('w') as fp:
3030
fp.write(
3131
DALS(

setuptools/tests/test_dist_info.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ def test_dist_info_is_the_same_as_in_wheel(
188188
dist_info = next(tmp_path.glob("dir_dist/*.dist-info"))
189189

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

setuptools/tests/test_easy_install.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import setuptools.command.easy_install as ei
2727
from pkg_resources import Distribution as PRDistribution, normalize_path, working_set
2828
from setuptools import sandbox
29+
from setuptools._normalization import safer_name
2930
from setuptools.command.easy_install import PthDistributions
3031
from setuptools.dist import Distribution
3132
from setuptools.sandbox import run_setup
@@ -669,11 +670,11 @@ def test_setup_requires_override_nspkg(self, use_setup_cfg):
669670

670671
with contexts.save_pkg_resources_state():
671672
with contexts.tempdir() as temp_dir:
672-
foobar_1_archive = os.path.join(temp_dir, 'foo.bar-0.1.tar.gz')
673+
foobar_1_archive = os.path.join(temp_dir, 'foo_bar-0.1.tar.gz')
673674
make_nspkg_sdist(foobar_1_archive, 'foo.bar', '0.1')
674675
# Now actually go ahead an extract to the temp dir and add the
675676
# extracted path to sys.path so foo.bar v0.1 is importable
676-
foobar_1_dir = os.path.join(temp_dir, 'foo.bar-0.1')
677+
foobar_1_dir = os.path.join(temp_dir, 'foo_bar-0.1')
677678
os.mkdir(foobar_1_dir)
678679
with tarfile.open(foobar_1_archive) as tf:
679680
tf.extraction_filter = lambda member, path: member
@@ -696,7 +697,7 @@ def test_setup_requires_override_nspkg(self, use_setup_cfg):
696697
len(foo.__path__) == 2):
697698
print('FAIL')
698699
699-
if 'foo.bar-0.2' not in foo.__path__[0]:
700+
if 'foo_bar-0.2' not in foo.__path__[0]:
700701
print('FAIL')
701702
"""
702703
)
@@ -717,8 +718,8 @@ def test_setup_requires_override_nspkg(self, use_setup_cfg):
717718
# Don't even need to install the package, just
718719
# running the setup.py at all is sufficient
719720
run_setup(test_setup_py, ['--name'])
720-
except pkg_resources.VersionConflict:
721-
self.fail(
721+
except pkg_resources.VersionConflict: # pragma: nocover
722+
pytest.fail(
722723
'Installing setup.py requirements caused a VersionConflict'
723724
)
724725

@@ -1118,6 +1119,8 @@ def make_nspkg_sdist(dist_path, distname, version):
11181119
package with the same name as distname. The top-level package is
11191120
designated a namespace package).
11201121
"""
1122+
# Assert that the distname contains at least one period
1123+
assert '.' in distname
11211124

11221125
parts = distname.split('.')
11231126
nspackage = parts[0]
@@ -1206,10 +1209,11 @@ def create_setup_requires_package(
12061209
package itself is just 'test_pkg'.
12071210
"""
12081211

1212+
normalized_distname = safer_name(distname)
12091213
test_setup_attrs = {
12101214
'name': 'test_pkg',
12111215
'version': '0.0',
1212-
'setup_requires': ['%s==%s' % (distname, version)],
1216+
'setup_requires': [f'{normalized_distname}=={version}'],
12131217
'dependency_links': [os.path.abspath(path)],
12141218
}
12151219
if setup_attrs:
@@ -1258,7 +1262,7 @@ def create_setup_requires_package(
12581262
with open(os.path.join(test_pkg, 'setup.py'), 'w', encoding="utf-8") as f:
12591263
f.write(setup_py_template % test_setup_attrs)
12601264

1261-
foobar_path = os.path.join(path, '%s-%s.tar.gz' % (distname, version))
1265+
foobar_path = os.path.join(path, f'{normalized_distname}-{version}.tar.gz')
12621266
make_package(foobar_path, distname, version)
12631267

12641268
return test_pkg

0 commit comments

Comments
 (0)