-
Notifications
You must be signed in to change notification settings - Fork 37
/
_pathutil.py
63 lines (48 loc) · 1.62 KB
/
_pathutil.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
from __future__ import annotations
import os
from pathlib import Path
from typing import TYPE_CHECKING
from ._file_processor import each_unignored_file
if TYPE_CHECKING:
from collections.abc import Generator, Sequence
__all__ = ["scantree", "path_to_module", "packages_to_file_mapping", "is_valid_module"]
def __dir__() -> list[str]:
return __all__
def scantree(path: Path) -> Generator[Path, None, None]:
"""Recursively yield Path objects for given directory."""
for entry in os.scandir(path):
if entry.is_dir(follow_symlinks=False):
yield from scantree(Path(entry))
else:
yield Path(entry)
def path_to_module(path: Path) -> str:
path = path.with_name(path.name.split(".", 1)[0])
if path.name == "__init__":
path = path.parent
return ".".join(path.parts)
def packages_to_file_mapping(
*,
packages: Sequence[str],
platlib_dir: Path,
include: Sequence[str],
exclude: Sequence[str],
) -> dict[str, str]:
mapping = {}
for package in packages:
source_package = Path(package)
base_path = source_package.parent
for filepath in each_unignored_file(
source_package,
include=include,
exclude=exclude,
):
package_dir = platlib_dir / filepath.relative_to(base_path)
if not package_dir.is_file():
mapping[str(filepath)] = str(package_dir)
return mapping
def is_valid_module(path: Path) -> bool:
parts = path.parts
return (
all(p.isidentifier() for p in parts[:-1])
and parts[-1].split(".", 1)[0].isidentifier()
)