[docs]defwalk_files(top:str|Path,max_depth:int=-1,exclude_dirs:set[str]|None=None,include_ext:set[str]|None=None,)->Iterator[Path]:""" Walk through the files recursively. :param top: Path to start from :type top: str | Path :param max_depth: Max recursion depth. If -1, there is no limit for recursion :type max_depth: int :param exclude_dirs: Dirs to exclude. No dirs are excluded by default, but it is recommended to exlude dirs such as __pycache__, .tox etc :type exclude_dirs: set[str] | None :param include_ext: Extensions to include. If None or empty, all extensions are included :type include_ext: set[str] | None :return: Generator that produces files satisfying all given values :rtype: Iterator[Path] """assertmax_depth>0ormax_depth==-1,"max_depth must be positive or -1"exclude_dirs=exclude_dirsorset()top=Path(top)ifmax_depth==0:returnforchildintop.iterdir():ifchild.is_file()and(notinclude_extorchild.name.split(".")[-1]ininclude_ext):yieldchildelif(child.is_dir()andchild.namenotinexclude_dirsandis_python_package(child)):yield fromwalk_files(child,max_depth-1ifmax_depth>0else-1)
[docs]defis_python_package(path:Path)->bool:""" Determine whether a given directory is a package or not. :param path: Path to the inspected dir :type path: Path :return: True if dir is a Python package, False otherwise :rtype: bool """forchildinpath.iterdir():ifnotchild.is_file():continueifchild.name=="__init__.py":returnTruereturnFalse
[docs]defmodule_name_from_path(file_path:Path,pkg_root:Path,pkg:str)->str:""" Compute importable module path. :param file_path: Path to the .py file :type file_path: Path :param pkg_root: Root of the package :type pkg_root: Path :param pkg: Package to import :type pkg: str :return: Importable path to module :rtype: str """rel=file_path.relative_to(pkg_root).with_suffix("")# strip .pyparts=rel.partsreturn".".join([pkg]+list(parts))