Source code for yieldplotlib.core.directory_node

"""Represents a directory containing multiple nodes (files or subdirectories)."""

from pathlib import Path

from tqdm import tqdm

from yieldplotlib.core.file_nodes import CSVFile, JSONFile, PickleFile
from yieldplotlib.core.node import Node
from yieldplotlib.logger import logger


[docs] class DirectoryNode(Node): """Represents a directory containing multiple nodes (files or subdirectories).""" def __init__(self, directory_path: Path): """Initialize the directory node with a list of children.""" super().__init__(directory_path) # Aliasing file_path to directory_path for consistency self.directory_path = self.file_path self.directory_name = self.directory_path.name self._children = [] self.load()
[docs] def load(self): """Recursively scan directories and load all child nodes.""" paths = list(self.directory_path.iterdir()) with tqdm( total=len(paths), desc=f"Loading {self.__class__.__name__} {self.directory_path.name}", unit="item", ) as pbar: for path in paths: if path.is_dir(): self.add(self._create_directory_node(path)) else: self.add(self._create_file_node(path)) pbar.update(1) # Establish the input node input_files = [child for child in self._children if child.is_input] if len(input_files) == 0: logger.warning("No input files found") self.input = None elif len(input_files) == 1: self.input = input_files[0] else: logger.warning("Multiple input files found, using the first") self.input = input_files[0]
[docs] def add(self, node: Node): """Add a child node to the directory.""" if node is not None: self._children.append(node)
[docs] def get(self, key: str, **kwargs): """Recursively search for data associated with the given key.""" for child in self._children: result = child.get(key, **kwargs) if result is not None: return result return None
[docs] def display_tree(self, level=0, max_children=5, prefix=""): """Recursively display the tree structure. Args: level (int): The current level of the tree. max_children (int): The maximum number of children to display. prefix (str): The prefix to display at the current level. """ repr_str = f"{prefix}{self.__repr__()}\n" # Adjust prefix for children child_prefix = prefix.replace("├── ", "│ ").replace("└── ", " ") for i, child in enumerate(self._children): # Adjust connector based on whether this is the last child last_before_cutoff = i == max_children - 1 last_child = i == len(self._children) - 1 # Determine the connector based on the child's position if last_before_cutoff and not last_child: connector = "├── " elif last_child: connector = "└── " else: connector = "├── " if i < max_children: repr_str += child.display_tree( level + 1, max_children, child_prefix + connector ) else: repr_str += ( f"{child_prefix}└── ... and" f" {len(self._children) - max_children} more\n" ) break return repr_str
[docs] def _create_directory_node(self, path: Path) -> Node: """Create a directory node for the given path.""" return self.create_base_directory(path)
[docs] def _create_file_node(self, path: Path) -> Node: """Create a file node for the given path.""" return self.create_base_file(path)
[docs] def create_base_file(self, path: Path): """Create a base file node for the given path.""" if path.suffix == ".csv": return CSVFile(path) elif path.suffix == ".json": return JSONFile(path) elif path.suffix == ".pkl": return PickleFile(path) else: logger.warning(f"Unknown file type: {path.suffix}") return None
[docs] def create_base_directory(self, path: Path): """Create a directory node for the given path.""" return DirectoryNode(path)