Source code for susi_lib.finder

"""Contains the :py:class:`Finder` class for searching in text."""

from collections.abc import Callable
from typing import Literal, overload


[docs] class Finder: """Class for finding words that satisfy all user provided functions. Supports lazy iteration with ``for`` over all matches. """ def __init__(self, inp: str | list[str], *functions: Callable[[str], bool]) -> None: """Creates new :py:class:`Finder` instance. :raises: :py:class:`TypeError` when invalid parameter types are passed :param inp: Input data. Either a filename or a list[str] containing individual lines :param functions: Functions that will determine wether a word is wanted or not """ if isinstance(inp, str): with open(inp, "r", encoding="utf-8") as f: self.__text: list[str] = [] for line in f: self.__text.append(line.strip()) elif isinstance(inp, list): self.__text = inp else: raise TypeError( "Inp must be a string with filename or list[str] with some data" ) for f in functions: if not callable(f): raise TypeError("All functions must be callable") self.__function = list(functions) def __valid_word(self, word: str): for f in self.__function: if not f(word): return False return True @overload def __execute(self, first: Literal[True]) -> str | None: ... @overload def __execute(self, first: Literal[False]) -> list[str]: ... def __execute(self, first: bool): result = [] for word in self.__text: if self.__valid_word(word): if first: return word result.append(word) return result if not first else None def __iter__(self): for word in self.__text: if self.__valid_word(word): yield word
[docs] def find_first(self) -> str | None: """Finds the first occurrence of a valid word and returns it. :return: The found word or None if no valid words are found """ return self.__execute(True)
[docs] def find_all(self) -> list[str]: """Finds all occurrences of a valid words and returns them. :return: List of found valid words """ return self.__execute(False)
[docs] def change_function(self, *functions: Callable[[str], bool]) -> None: """Changes functions for other functions. :raises: :py:class:`TypeError` when invalid parameter types are passed :param functions: New list of functions """ for f in functions: if not callable(f): raise TypeError("All functions must be callable") self.__function = list(functions)
[docs] def add_function(self, *functions: Callable[[str], bool]) -> None: """Adds new functions to constraint valid words. :param functions: New functions to add """ for f in functions: if not callable(f): raise TypeError("All functions must be callable") self.__function.extend(functions)