Skip to content

Commit 01e64e9

Browse files
authored
Merge pull request #400 from sbidoul/pep517-editable-sbi
PEP 660 support
2 parents 734ab12 + 2444dc2 commit 01e64e9

File tree

5 files changed

+92
-6
lines changed

5 files changed

+92
-6
lines changed

flit/wheel.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
log = logging.getLogger(__name__)
66

7-
def make_wheel_in(ini_path, wheel_directory):
8-
return core_wheel.make_wheel_in(ini_path, wheel_directory)
7+
def make_wheel_in(ini_path, wheel_directory, editable=False):
8+
return core_wheel.make_wheel_in(ini_path, wheel_directory, editable)
99

1010
class WheelBuilder(core_wheel.WheelBuilder):
1111
pass

flit_core/flit_core/buildapi.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ def get_requires_for_build_wheel(config_settings=None):
3939
# Requirements to build an sdist are the same as for a wheel
4040
get_requires_for_build_sdist = get_requires_for_build_wheel
4141

42+
# Requirements to build an editable are the same as for a wheel
43+
get_requires_for_build_editable = get_requires_for_build_wheel
44+
4245
def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
4346
"""Creates {metadata_directory}/foo-1.2.dist-info"""
4447
ini_info = read_flit_config(pyproj_toml)
@@ -61,11 +64,19 @@ def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
6164

6265
return osp.basename(dist_info)
6366

67+
# Metadata for editable are the same as for a wheel
68+
prepare_metadata_for_build_editable = prepare_metadata_for_build_wheel
69+
6470
def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
6571
"""Builds a wheel, places it in wheel_directory"""
6672
info = make_wheel_in(pyproj_toml, Path(wheel_directory))
6773
return info.file.name
6874

75+
def build_editable(wheel_directory, config_settings=None, metadata_directory=None):
76+
"""Builds an "editable" wheel, places it in wheel_directory"""
77+
info = make_wheel_in(pyproj_toml, Path(wheel_directory), editable=True)
78+
return info.file.name
79+
6980
def build_sdist(sdist_directory, config_settings=None):
7081
"""Builds an sdist, places it in sdist_directory"""
7182
path = SdistBuilder.from_ini_path(pyproj_toml).build(Path(sdist_directory))

flit_core/flit_core/tests/test_buildapi.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ def test_get_build_requires():
2424
# importing it, so there are no build dependencies.
2525
with cwd(osp.join(samples_dir,'pep517')):
2626
assert buildapi.get_requires_for_build_wheel() == []
27+
assert buildapi.get_requires_for_build_editable() == []
2728
assert buildapi.get_requires_for_build_sdist() == []
2829

2930
def test_get_build_requires_pep621_nodynamic():
3031
# This module isn't inspected because version & description are specified
3132
# as static metadata in pyproject.toml, so there are no build dependencies
3233
with cwd(osp.join(samples_dir, 'pep621_nodynamic')):
3334
assert buildapi.get_requires_for_build_wheel() == []
35+
assert buildapi.get_requires_for_build_editable() == []
3436
assert buildapi.get_requires_for_build_sdist() == []
3537

3638
def test_get_build_requires_import():
@@ -39,6 +41,7 @@ def test_get_build_requires_import():
3941
expected = ["numpy >=1.16.0"]
4042
with cwd(osp.join(samples_dir, 'constructed_version')):
4143
assert buildapi.get_requires_for_build_wheel() == expected
44+
assert buildapi.get_requires_for_build_editable() == expected
4245
assert buildapi.get_requires_for_build_sdist() == expected
4346

4447
def test_build_wheel():
@@ -47,6 +50,9 @@ def test_build_wheel():
4750
assert filename.endswith('.whl'), filename
4851
assert_isfile(osp.join(td, filename))
4952
assert zipfile.is_zipfile(osp.join(td, filename))
53+
with zipfile.ZipFile(osp.join(td, filename)) as zip:
54+
assert "module1.py" in zip.namelist()
55+
assert "module1.pth" not in zip.namelist()
5056

5157
def test_build_wheel_pep621():
5258
with TemporaryDirectory() as td, cwd(osp.join(samples_dir, 'pep621')):
@@ -55,6 +61,16 @@ def test_build_wheel_pep621():
5561
assert_isfile(osp.join(td, filename))
5662
assert zipfile.is_zipfile(osp.join(td, filename))
5763

64+
def test_build_editable():
65+
with TemporaryDirectory() as td, cwd(osp.join(samples_dir,'pep517')):
66+
filename = buildapi.build_editable(td)
67+
assert filename.endswith('.whl'), filename
68+
assert_isfile(osp.join(td, filename))
69+
assert zipfile.is_zipfile(osp.join(td, filename))
70+
with zipfile.ZipFile(osp.join(td, filename)) as zip:
71+
assert "module1.py" not in zip.namelist()
72+
assert "module1.pth" in zip.namelist()
73+
5874
def test_build_sdist():
5975
with TemporaryDirectory() as td, cwd(osp.join(samples_dir,'pep517')):
6076
filename = buildapi.build_sdist(td)
@@ -68,3 +84,10 @@ def test_prepare_metadata_for_build_wheel():
6884
assert dirname.endswith('.dist-info'), dirname
6985
assert_isdir(osp.join(td, dirname))
7086
assert_isfile(osp.join(td, dirname, 'METADATA'))
87+
88+
def test_prepare_metadata_for_build_editable():
89+
with TemporaryDirectory() as td, cwd(osp.join(samples_dir,'pep517')):
90+
dirname = buildapi.prepare_metadata_for_build_editable(td)
91+
assert dirname.endswith('.dist-info'), dirname
92+
assert_isdir(osp.join(td, dirname))
93+
assert_isfile(osp.join(td, dirname, 'METADATA'))

flit_core/flit_core/wheel.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ def copy_module(self):
146146
rel_path = osp.relpath(full_path, source_dir)
147147
self._add_file(full_path, rel_path)
148148

149+
def add_pth(self):
150+
with self._write_to_zip(self.module.name + ".pth") as f:
151+
f.write(str(self.module.source_dir))
152+
149153
def write_metadata(self):
150154
log.info('Writing metadata files')
151155

@@ -173,22 +177,25 @@ def write_record(self):
173177
# RECORD itself is recorded with no hash or size
174178
f.write(self.dist_info + '/RECORD,,\n')
175179

176-
def build(self):
180+
def build(self, editable=False):
177181
try:
178-
self.copy_module()
182+
if editable:
183+
self.add_pth()
184+
else:
185+
self.copy_module()
179186
self.write_metadata()
180187
self.write_record()
181188
finally:
182189
self.wheel_zip.close()
183190

184-
def make_wheel_in(ini_path, wheel_directory):
191+
def make_wheel_in(ini_path, wheel_directory, editable=False):
185192
# We don't know the final filename until metadata is loaded, so write to
186193
# a temporary_file, and rename it afterwards.
187194
(fd, temp_path) = tempfile.mkstemp(suffix='.whl', dir=str(wheel_directory))
188195
try:
189196
with io.open(fd, 'w+b') as fp:
190197
wb = WheelBuilder.from_ini_path(ini_path, fp)
191-
wb.build()
198+
wb.build(editable)
192199

193200
wheel_path = wheel_directory / wb.wheel_filename
194201
os.replace(temp_path, str(wheel_path))

tests/test_wheel.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,33 @@ def test_wheel_module(copy_sample):
2525
make_wheel_in(td / 'pyproject.toml', td)
2626
assert_isfile(td / 'module1-0.1-py2.py3-none-any.whl')
2727

28+
def test_editable_wheel_module(copy_sample):
29+
td = copy_sample('module1_toml')
30+
make_wheel_in(td / 'pyproject.toml', td, editable=True)
31+
whl_file = td / 'module1-0.1-py2.py3-none-any.whl'
32+
assert_isfile(whl_file)
33+
with unpack(whl_file) as unpacked:
34+
pth_path = Path(unpacked, 'module1.pth')
35+
assert_isfile(pth_path)
36+
assert pth_path.read_text() == str(td)
37+
assert_isdir(Path(unpacked, 'module1-0.1.dist-info'))
38+
2839
def test_wheel_package(copy_sample):
2940
td = copy_sample('package1')
3041
make_wheel_in(td / 'pyproject.toml', td)
3142
assert_isfile(td / 'package1-0.1-py2.py3-none-any.whl')
3243

44+
def test_editable_wheel_package(copy_sample):
45+
td = copy_sample('package1')
46+
make_wheel_in(td / 'pyproject.toml', td, editable=True)
47+
whl_file = td / 'package1-0.1-py2.py3-none-any.whl'
48+
assert_isfile(whl_file)
49+
with unpack(whl_file) as unpacked:
50+
pth_path = Path(unpacked, 'package1.pth')
51+
assert_isfile(pth_path)
52+
assert pth_path.read_text() == str(td)
53+
assert_isdir(Path(unpacked, 'package1-0.1.dist-info'))
54+
3355
def test_wheel_src_module(copy_sample):
3456
td = copy_sample('module3')
3557
make_wheel_in(td / 'pyproject.toml', td)
@@ -41,6 +63,17 @@ def test_wheel_src_module(copy_sample):
4163
assert_isdir(Path(unpacked, 'module3-0.1.dist-info'))
4264
assert_isfile(Path(unpacked, 'module3-0.1.dist-info', 'LICENSE'))
4365

66+
def test_editable_wheel_src_module(copy_sample):
67+
td = copy_sample('module3')
68+
make_wheel_in(td / 'pyproject.toml', td, editable=True)
69+
whl_file = td / 'module3-0.1-py2.py3-none-any.whl'
70+
assert_isfile(whl_file)
71+
with unpack(whl_file) as unpacked:
72+
pth_path = Path(unpacked, 'module3.pth')
73+
assert_isfile(pth_path)
74+
assert pth_path.read_text() == str(td / "src")
75+
assert_isdir(Path(unpacked, 'module3-0.1.dist-info'))
76+
4477
def test_wheel_src_package(copy_sample):
4578
td = copy_sample('package2')
4679
make_wheel_in(td / 'pyproject.toml', td)
@@ -51,6 +84,18 @@ def test_wheel_src_package(copy_sample):
5184
print(os.listdir(unpacked))
5285
assert_isfile(Path(unpacked, 'package2', '__init__.py'))
5386

87+
def test_editable_wheel_src_package(copy_sample):
88+
td = copy_sample('package2')
89+
make_wheel_in(td / 'pyproject.toml', td, editable=True)
90+
whl_file = td / 'package2-0.1-py2.py3-none-any.whl'
91+
assert_isfile(whl_file)
92+
with unpack(whl_file) as unpacked:
93+
pth_path = Path(unpacked, 'package2.pth')
94+
assert_isfile(pth_path)
95+
assert pth_path.read_text() == str(td / "src")
96+
assert_isdir(Path(unpacked, 'package2-0.1.dist-info'))
97+
98+
5499
def test_dist_name(copy_sample):
55100
td = copy_sample('altdistname')
56101
make_wheel_in(td / 'pyproject.toml', td)

0 commit comments

Comments
 (0)