Source code for cfinterface.data.sectiondata

from typing import TypeVar, Type, Generator, Optional, Union, List

from cfinterface.components.section import Section


[docs] class SectionData: """ Class for a storing, managing and accessing data for a section file. """ __slots__ = ["__root", "__head"] T = TypeVar("T") def __init__(self, root: Section) -> None: self.__root = root self.__head = root def __iter__(self): current = self.__root while current: yield current current = current.next def __len__(self) -> int: count = 0 for _ in self: count += 1 return count def __eq__(self, o: object) -> bool: if not isinstance(o, SectionData): return False sd: SectionData = o if len(self) != len(sd): return False for r1, r2 in zip(self, sd): if r1 != r2: return False return True
[docs] def preppend(self, s: Section): """ Appends a section to the beginning of the data. :param s: The new section to preppended to the data. :type s: Section """ self.add_before(self.__root, s)
[docs] def append(self, s: Section): """ Appends a section to the end of the data. :param s: The new section to append to the data :type s: Section """ self.add_after(self.__head, s)
[docs] def add_before(self, before: Section, new: Section): """ Adds a new section to the data before another specified section. :param before: The existing section which will be preppended :type before: Section :param new: The new section to add to the data :type new: Section """ if before == self.__root: self.__root = new else: if before.previous: before.previous.next = new new.previous = before.previous before.previous = new new.next = before
[docs] def add_after(self, after: Section, new: Section): """ Adds a new section to the data after another specified section. :param after: The existing section which will be appended :type after: Section :param new: The new section to add to the data :type new: Section """ if after == self.__head: self.__head = new else: if after.next: after.next.previous = new new.next = after.next after.next = new new.previous = after
[docs] def remove(self, s: Section): """ Removes an existing section in the chain. :param s: The section to be removed :type s: Section """ if s.previous is not None: s.previous.next = s.next if s.next is not None: s.next.previous = s.previous
[docs] def of_type(self, t: Type[T]) -> Generator[T, None, None]: """ A section generator that only returns sections of type T. :param t: The section type that is desired :type t: Type[T] :yield: Sections filtered by type T :rtype: Generator[T, None, None] """ for s in self: if isinstance(s, t): yield s
[docs] def get_sections_of_type( self, t: Type[T], **kwargs ) -> Optional[Union[T, List[T]]]: """ A section or section list that only returns sections of type T that meet given filter requirements passed as kwargs. :param t: The section type that is desired :type t: Type[T] :return: Sections filtered by type T and optional properties :rtype: T | list[T] | None """ def __meets(r) -> bool: conditions: List[bool] = [] for k, v in kwargs.items(): if v is not None: conditions.append(getattr(r, k) == v) return all(conditions) all_sections_of_type = [b for b in self.of_type(t)] filtered_sections = [r for r in all_sections_of_type if __meets(r)] if len(filtered_sections) == 0: return None elif len(filtered_sections) == 1: return filtered_sections[0] else: return filtered_sections
[docs] def remove_sections_of_type(self, t: Type[T], **kwargs): """ Removes a set of sections given a type and an optional group of filters, similar to `get_sections_of_type()` :param t: The section type that is desired :type t: Type[T] """ filtered_sections = self.get_sections_of_type(t, **kwargs) if isinstance(filtered_sections, t) and isinstance( filtered_sections, Section ): self.remove(filtered_sections) elif isinstance(filtered_sections, list): for s in filtered_sections: if isinstance(s, Section) and s != self.__root: self.remove(s)
@property def first(self) -> Section: return self.__root @property def last(self) -> Section: return self.__head