Source code for ten8t.ten8t_util

"""
This is the sad place for lonely functions that don't have a place
"""
import pathlib
from typing import Sequence, TypeAlias

# Type aliases.
# Note: the *OrNone are meant to be constructors that allow a None value to be passed
#       that code will take care to convert to a [] or a ''
StrOrNone: TypeAlias = str | None
"""Type alias for a string or None."""

StrList: TypeAlias = Sequence[str]
"""Type alias for a sequence of strings."""

StrListOrNone: TypeAlias = StrList | StrOrNone
"""Type alias for a sequence of strings or None."""

IntOrNone: TypeAlias = int | None
"""Type alias for an integer or None."""

IntList: TypeAlias = Sequence[int]
"""Type alias for a sequence of integers."""

IntListOrNone: TypeAlias = IntList | IntOrNone
"""Type alias for a sequence of integers or None."""

FloatOrNone: TypeAlias = float | None
"""Type alias for a float or None."""

FloatList: TypeAlias = Sequence[float]
"""Type alias for a sequence of floats."""

FloatListOrNone: TypeAlias = FloatList | FloatOrNone
"""Type alias for a sequence of floats or None."""

StrOrPath: TypeAlias = str | pathlib.Path
StrOrPathOrNone: TypeAlias = StrOrPath | None
StrOrPathList: TypeAlias = Sequence[StrOrPath]
StrOrPathListOrNone: TypeAlias = StrOrPathList | None

PathList: TypeAlias = Sequence[pathlib.Path]

[docs] class NextIntValue: """ I had to create this class in order to make mypy happy. Mypy does not know how to handle dynamic functions and playing games """ def __init__(self): self.current_id: int = 1 # Initialize to 1 def __call__(self) -> int: self.current_id += 1 return self.current_id
# Create an instance of the callable class next_int_value = NextIntValue() # next_int_value can be called like a function and the class manages the count next_int_value.current_id = 1
[docs] def str_to_bool(s: str, default=None) -> bool: """ Convert a string value to a boolean.""" s = s.strip().lower() # Remove spaces at the beginning/end and convert to lower case if s in ('pass', 'true', 'yes', '1', 't', 'y', 'on'): return True if s in ('fail', 'false', 'no', '0', 'f', 'n', 'off'): return False if default is not None: return default raise ValueError(f'Cannot convert {s} to a boolean.')
[docs] def any_to_str_list(param: StrListOrNone, sep=' ') -> StrList: """ Convert a string to a list of strings or if a list is given make sure it is all strings. Args: param: list of strings or string to convert to list of strings sep: separator character. Returns: """ if param is None: return [] if isinstance(param, str): param = param.strip() if param == '': return [] else: return param.split(sep) if isinstance(param, list): if all(isinstance(item, str) for item in param): return param raise ValueError(f'Invalid parameter type, expected all strings. {param}')
[docs] def any_to_path_list(param: StrOrPathListOrNone, sep=' ') -> PathList: """ Flexibly take a list of strings are pathlib objects and make a uniform list of pathlib objects. This is useful for normalizing data read from different sources without have a bunch of point of use parsing. The assumption is that this data could come from a config file, a command line parameter, a UI element that returns strings, or code. This should make all code just "fix" the data with this call. Args: param: StrOrPathListOrNone Data to normalize sep: Separator character. Should almost always be ' ' Returns: """ if param is None: return [] # Listify single path if isinstance(param, (pathlib.Path)): param = [param] # Given a string make it a list of strings if isinstance(param, str): param = param.strip() if param == '': param = [] else: # Space split is slightly different and preferable if sep == ' ': param = param.split() else: param = param.split(sep) # Now we have a list of paths and strings, covert them all th paths return [pathlib.Path(p) for p in param]
[docs] def any_to_int_list(param: IntListOrNone, sep=' ') -> IntList: """ Convert a string to a list of integers or if a list is given make sure it is all integers. Args: param: list of integers or string to convert to list of integers sep: separator character. Returns: list of integers """ if param is None: return [] if isinstance(param, str): param = param.strip() cleaned_param = param.split(sep) try: return [int(x) for x in cleaned_param] except ValueError as exc: raise ValueError( 'Invalid parameter value, expected numeric string values that can be converted to integers.') from exc if isinstance(param, list): return [int(x) for x in param] raise ValueError(f'Invalid parameter type in {param}, expected all integers.')