Skip to content

Commit

Permalink
Address review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
eltoder committed Mar 24, 2024
1 parent 8a58ef1 commit 682c688
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 9 deletions.
31 changes: 22 additions & 9 deletions src/slotscheck/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from functools import partial, reduce
from importlib.util import find_spec
from inspect import isclass
from itertools import chain, takewhile
from itertools import chain
from pathlib import Path
from textwrap import indent
from types import ModuleType
Expand Down Expand Up @@ -300,19 +300,32 @@ def _is_package(p: AbsPath) -> bool:
return p.is_dir() and (p / _INIT_PY).is_file()


def find_modules(
p: AbsPath, python_path: Optional[FrozenSet[AbsPath]] = None
def _module_parents(
p: AbsPath, sys_path: FrozenSet[AbsPath]
) -> Iterable[AbsPath]:
yield p
for pp in p.parents:
if pp in sys_path:
return
yield pp
raise ValueError(f"File {p} is outside of PYTHONPATH ({sys.path})")


def _find_modules(
p: AbsPath, sys_path: FrozenSet[AbsPath]
) -> Iterable[ModuleLocated]:
"Recursively find modules at given path. Nonexistent Path is ignored"
if python_path is None:
python_path = frozenset(map(Path, sys.path))
if p.name == _INIT_PY:
yield from find_modules(p.parent, python_path)
yield from _find_modules(p.parent, sys_path)
elif _is_module(p):
parents = [p, *takewhile(lambda p: p not in python_path, p.parents)]
parents = list(_module_parents(p, sys_path))
yield ModuleLocated(
".".join(p.stem for p in reversed(parents)),
(p / _INIT_PY if _is_package(p) else p),
)
elif p.is_dir():
yield from flatten(find_modules(sp, python_path) for sp in p.iterdir())
yield from flatten(_find_modules(cp, sys_path) for cp in p.iterdir())


def find_modules(p: AbsPath) -> Iterable[ModuleLocated]:
"Recursively find modules at given path. Nonexistent Path is ignored"
return _find_modules(p, frozenset(map(Path, sys.path)))
10 changes: 10 additions & 0 deletions tests/src/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,16 @@ def test_multiple_modules(runner: CliRunner):
assert result.output == "All OK!\nScanned 11 module(s), 70 class(es).\n"


def test_implicitly_namespaced_path(runner: CliRunner):
result = runner.invoke(
cli,
[str(EXAMPLES_DIR / "implicitly_namespaced")],
catch_exceptions=False,
)
assert result.exit_code == 0
assert result.output == "All OK!\nScanned 7 module(s), 1 class(es).\n"


def test_multiple_paths(runner: CliRunner):
result = runner.invoke(
cli,
Expand Down
6 changes: 6 additions & 0 deletions tests/src/test_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,12 @@ def test_given_init_py(self):
ModuleLocated("files.subdir.some_module.sub", location)
]

def test_given_file_not_in_sys_path(self, tmp_path):
location = tmp_path / "foo.py"
location.touch()
with pytest.raises(ValueError, match="is outside of PYTHONPATH"):
list(find_modules(location))


class TestConsolidate:
def test_empty(self):
Expand Down

0 comments on commit 682c688

Please sign in to comment.