Skip to content

Commit 2137d89

Browse files
authored
Fix the wheel target for case insensitive file systems (#1080)
* Fix the `wheel` target for case insensitive file systems * address feedback
1 parent 751b8ca commit 2137d89

File tree

3 files changed

+39
-5
lines changed

3 files changed

+39
-5
lines changed

backend/src/hatchling/builders/wheel.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import hashlib
55
import os
66
import stat
7+
import sys
78
import tempfile
89
import zipfile
910
from io import StringIO
@@ -178,15 +179,19 @@ def set_default_file_selection(self) -> None:
178179
self.builder.normalize_file_name_component(self.builder.metadata.core.name),
179180
):
180181
if os.path.isfile(os.path.join(self.root, project_name, '__init__.py')):
181-
self.__packages.append(project_name)
182+
normalized_project_name = self.get_raw_fs_path_name(self.root, project_name)
183+
self.__packages.append(normalized_project_name)
182184
break
183185

184186
if os.path.isfile(os.path.join(self.root, 'src', project_name, '__init__.py')):
185-
self.__packages.append(f'src/{project_name}')
187+
normalized_project_name = self.get_raw_fs_path_name(os.path.join(self.root, 'src'), project_name)
188+
self.__packages.append(f'src/{normalized_project_name}')
186189
break
187190

188-
if os.path.isfile(os.path.join(self.root, f'{project_name}.py')):
189-
self.__only_include.append(f'{project_name}.py')
191+
module_file = f'{project_name}.py'
192+
if os.path.isfile(os.path.join(self.root, module_file)):
193+
normalized_project_name = self.get_raw_fs_path_name(self.root, module_file)
194+
self.__only_include.append(module_file)
190195
break
191196

192197
from glob import glob
@@ -344,6 +349,24 @@ def macos_max_compat(self) -> bool:
344349

345350
return self.__macos_max_compat
346351

352+
if sys.platform in {'darwin', 'win32'}:
353+
354+
@staticmethod
355+
def get_raw_fs_path_name(directory: str, name: str) -> str:
356+
normalized = name.casefold()
357+
entries = os.listdir(directory)
358+
for entry in entries:
359+
if entry.casefold() == normalized:
360+
return entry
361+
362+
return name # no cov
363+
364+
else:
365+
366+
@staticmethod
367+
def get_raw_fs_path_name(directory: str, name: str) -> str: # noqa: ARG004
368+
return name
369+
347370

348371
class WheelBuilder(BuilderInterface):
349372
"""

docs/history/hatchling.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
2121
- Fix parsing dependencies for environments when warnings are emitted
2222
- Properly handle non-zero version epoch for the `standard` version scheme
2323
- Allow using an empty string for the `sources` option to add a prefix to distribution paths
24+
- Fix the `wheel` target for case insensitive file systems when the project metadata name does not match the directory name on disk
2425

2526
## [1.18.0](https://github.com/pypa/hatch/releases/tag/hatchling-v1.18.0) - 2023-06-12 ## {: #hatchling-v1.18.0 }
2627

tests/backend/builders/test_wheel.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def test_default(self, temp_dir):
121121
assert builder.config.default_packages() == []
122122
assert builder.config.default_only_include() == []
123123

124-
def test_raw_name_not_normalized(self, temp_dir):
124+
def test_unnormalized_name_with_unnormalized_directory(self, temp_dir):
125125
config = {'project': {'name': 'MyApp', 'version': '0.0.1'}}
126126
builder = WheelBuilder(str(temp_dir), config=config)
127127

@@ -131,6 +131,16 @@ def test_raw_name_not_normalized(self, temp_dir):
131131

132132
assert builder.config.default_packages() == ['src/MyApp']
133133

134+
def test_unnormalized_name_with_normalized_directory(self, temp_dir):
135+
config = {'project': {'name': 'MyApp', 'version': '0.0.1'}}
136+
builder = WheelBuilder(str(temp_dir), config=config)
137+
138+
src_root = temp_dir / 'src' / 'myapp' / '__init__.py'
139+
src_root.ensure_parent_dir_exists()
140+
src_root.touch()
141+
142+
assert builder.config.default_packages() == ['src/myapp']
143+
134144

135145
class TestCoreMetadataConstructor:
136146
def test_default(self, isolation):

0 commit comments

Comments
 (0)