Spaces:
Running
Running
from typing import Dict, List | |
from .glob_group import GlobGroup, GlobPattern | |
__all__ = ["Directory"] | |
class Directory: | |
"""A file structure representation. Organized as Directory nodes that have lists of | |
their Directory children. Directories for a package are created by calling | |
:meth:`PackageImporter.file_structure`.""" | |
def __init__(self, name: str, is_dir: bool): | |
self.name = name | |
self.is_dir = is_dir | |
self.children: Dict[str, Directory] = {} | |
def _get_dir(self, dirs: List[str]) -> "Directory": | |
"""Builds path of Directories if not yet built and returns last directory | |
in list. | |
Args: | |
dirs (List[str]): List of directory names that are treated like a path. | |
Returns: | |
:class:`Directory`: The last Directory specified in the dirs list. | |
""" | |
if len(dirs) == 0: | |
return self | |
dir_name = dirs[0] | |
if dir_name not in self.children: | |
self.children[dir_name] = Directory(dir_name, True) | |
return self.children[dir_name]._get_dir(dirs[1:]) | |
def _add_file(self, file_path: str): | |
"""Adds a file to a Directory. | |
Args: | |
file_path (str): Path of file to add. Last element is added as a file while | |
other paths items are added as directories. | |
""" | |
*dirs, file = file_path.split("/") | |
dir = self._get_dir(dirs) | |
dir.children[file] = Directory(file, False) | |
def has_file(self, filename: str) -> bool: | |
"""Checks if a file is present in a :class:`Directory`. | |
Args: | |
filename (str): Path of file to search for. | |
Returns: | |
bool: If a :class:`Directory` contains the specified file. | |
""" | |
lineage = filename.split("/", maxsplit=1) | |
child = lineage[0] | |
grandchildren = lineage[1] if len(lineage) > 1 else None | |
if child in self.children.keys(): | |
if grandchildren is None: | |
return True | |
else: | |
return self.children[child].has_file(grandchildren) | |
return False | |
def __str__(self): | |
str_list: List[str] = [] | |
self._stringify_tree(str_list) | |
return "".join(str_list) | |
def _stringify_tree( | |
self, str_list: List[str], preamble: str = "", dir_ptr: str = "βββ " | |
): | |
"""Recursive method to generate print-friendly version of a Directory.""" | |
space = " " | |
branch = "β " | |
tee = "βββ " | |
last = "βββ " | |
# add this directory's representation | |
str_list.append(f"{preamble}{dir_ptr}{self.name}\n") | |
# add directory's children representations | |
if dir_ptr == tee: | |
preamble = preamble + branch | |
else: | |
preamble = preamble + space | |
file_keys: List[str] = [] | |
dir_keys: List[str] = [] | |
for key, val in self.children.items(): | |
if val.is_dir: | |
dir_keys.append(key) | |
else: | |
file_keys.append(key) | |
for index, key in enumerate(sorted(dir_keys)): | |
if (index == len(dir_keys) - 1) and len(file_keys) == 0: | |
self.children[key]._stringify_tree(str_list, preamble, last) | |
else: | |
self.children[key]._stringify_tree(str_list, preamble, tee) | |
for index, file in enumerate(sorted(file_keys)): | |
pointer = last if (index == len(file_keys) - 1) else tee | |
str_list.append(f"{preamble}{pointer}{file}\n") | |
def _create_directory_from_file_list( | |
filename: str, | |
file_list: List[str], | |
include: "GlobPattern" = "**", | |
exclude: "GlobPattern" = (), | |
) -> Directory: | |
"""Return a :class:`Directory` file structure representation created from a list of files. | |
Args: | |
filename (str): The name given to the top-level directory that will be the | |
relative root for all file paths found in the file_list. | |
file_list (List[str]): List of files to add to the top-level directory. | |
include (Union[List[str], str]): An optional pattern that limits what is included from the file_list to | |
files whose name matches the pattern. | |
exclude (Union[List[str], str]): An optional pattern that excludes files whose name match the pattern. | |
Returns: | |
:class:`Directory`: a :class:`Directory` file structure representation created from a list of files. | |
""" | |
glob_pattern = GlobGroup(include, exclude=exclude, separator="/") | |
top_dir = Directory(filename, True) | |
for file in file_list: | |
if glob_pattern.matches(file): | |
top_dir._add_file(file) | |
return top_dir | |