Spaces:
Running
Running
File size: 4,833 Bytes
c61ccee |
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
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
|