Skip to content

Commit c67578c

Browse files
dnicolodirgommers
authored andcommitted
ENH: respect exclude_dirs and exclude_files in editable installs
Add support for the exclude_dirs and exclude_files arguments of install_subdir() Meson function. Extend editable install tests to cover this functionality and a more complex package layout.
1 parent f5a50b1 commit c67578c

File tree

2 files changed

+25
-13
lines changed

2 files changed

+25
-13
lines changed

mesonpy/_editable.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -221,13 +221,21 @@ def get(self, key: Union[str, Tuple[str, ...]]) -> Optional[Union[Node, str]]:
221221
return dict.get(node, key)
222222

223223

224-
def walk(root: str, path: str = '') -> Iterator[pathlib.Path]:
225-
with os.scandir(os.path.join(root, path)) as entries:
226-
for entry in entries:
227-
if entry.is_dir():
228-
yield from walk(root, os.path.join(path, entry.name))
229-
else:
230-
yield pathlib.Path(path, entry.name)
224+
def walk(src: str, exclude_files: Set[str], exclude_dirs: Set[str]) -> Iterator[str]:
225+
for root, dirnames, filenames in os.walk(src):
226+
for name in dirnames.copy():
227+
dirsrc = os.path.join(root, name)
228+
relpath = os.path.relpath(dirsrc, src)
229+
if relpath in exclude_dirs:
230+
dirnames.remove(name)
231+
# sort to process directories determninistically
232+
dirnames.sort()
233+
for name in sorted(filenames):
234+
filesrc = os.path.join(root, name)
235+
relpath = os.path.relpath(filesrc, src)
236+
if relpath in exclude_files:
237+
continue
238+
yield relpath
231239

232240

233241
def collect(install_plan: Dict[str, Dict[str, Any]]) -> Node:
@@ -237,8 +245,10 @@ def collect(install_plan: Dict[str, Dict[str, Any]]) -> Node:
237245
path = pathlib.Path(target['destination'])
238246
if path.parts[0] in {'{py_platlib}', '{py_purelib}'}:
239247
if key == 'install_subdirs' and os.path.isdir(src):
240-
for entry in walk(src):
241-
tree[(*path.parts[1:], *entry.parts)] = os.path.join(src, *entry.parts)
248+
exclude_files = {os.path.normpath(x) for x in target.get('exclude_files', [])}
249+
exclude_dirs = {os.path.normpath(x) for x in target.get('exclude_dirs', [])}
250+
for entry in walk(src, exclude_files, exclude_dirs):
251+
tree[(*path.parts[1:], *entry.split(os.sep))] = os.path.join(src, entry)
242252
else:
243253
tree[path.parts[1:]] = src
244254
return tree

tests/test_editable.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616

1717

1818
def test_walk(package_complex):
19-
entries = set(_editable.walk(os.fspath(package_complex / 'complex')))
20-
assert entries == {
19+
entries = _editable.walk(
20+
os.fspath(package_complex / 'complex'),
21+
[os.path.normpath('more/meson.build'), os.path.normpath('more/baz.pyx')],
22+
[os.path.normpath('namespace')],
23+
)
24+
assert {pathlib.Path(x) for x in entries} == {
2125
pathlib.Path('__init__.py'),
2226
pathlib.Path('more/__init__.py'),
23-
pathlib.Path('namespace/bar.py'),
24-
pathlib.Path('namespace/foo.py')
2527
}
2628

2729

0 commit comments

Comments
 (0)