""" Library of classes modeling software and software-related data as represented in or used by Ansible. """ from typing import TypeAlias as Neotype from typing import TypedDict as Dict from typing import Never, Union from custtypes import ExecutedPath, IdlePath from enum import Enum from pathlib import Path, PurePath from whereami import USER_PATH, PROJ_ROOT AppPath: Neotype = Union[ExecutedPath, IdlePath] class SoftScope(Enum): PERSONAL = 0 LOCAL = 1 GLOBAL = 2 class SoftPathGroup(Enum): CONFIG = 0 DATA = 1 MEM = 2 # @TODO continue adding magic methods to below class # @NOTE https://rszalski.github.io/magicmethods/#sequence class Software: # @TODO 2 options: add additional requirements to type definition below, # or ensure attribute which stores data of this type also stores other data _AppParams = Dict("_AppParams", { SoftPathGroup.CONFIG.name: { SoftScope.PERSONAL.name: IdlePath | list[IdlePath], SoftScope.LOCAL.name: IdlePath | list[IdlePath], SoftScope.GLOBAL.name: IdlePath | list[IdlePath] }, SoftPathGroup.DATA.name: { SoftScope.PERSONAL.name: IdlePath | list[IdlePath], SoftScope.LOCAL.name: IdlePath | list[IdlePath], SoftScope.GLOBAL.name: IdlePath | list[IdlePath] }, SoftPathGroup.MEM.name: { SoftScope.PERSONAL.name: IdlePath | list[IdlePath], SoftScope.LOCAL.name: IdlePath | list[IdlePath], SoftScope.GLOBAL.name: IdlePath | list[IdlePath] } }, total=False) _SubAppParams = Dict("_SubAppParams", { SoftScope.PERSONAL.name: IdlePath | list[IdlePath], SoftScope.LOCAL.name: IdlePath | list[IdlePath], SoftScope.GLOBAL.name: IdlePath | list[IdlePath] }, total=False) __app_input = { SoftPathGroup.CONFIG.name: { SoftScope.PERSONAL.name: [], SoftScope.LOCAL.name: [], SoftScope.GLOBAL.name: [] }, SoftPathGroup.DATA.name: { SoftScope.PERSONAL.name: [], SoftScope.LOCAL.name: [], SoftScope.GLOBAL.name: [] }, SoftPathGroup.MEM.name: { SoftScope.PERSONAL.name: [], SoftScope.LOCAL.name: [], SoftScope.GLOBAL.name: [] } } _Apps = type("_Apps", (), **__app_input) __user_path: ExecutedPath = USER_PATH def __init__(self): self._fqdn: str | None = None def declare(self, name: str, **kwpaths: Software._SubAppParams) -> Software._AppParams: keyword_args: Software._AppParams = kwpaths app = Software._Apps(**keyword_args) setattr(self, name, app) return app def __getitem__(self, key: str) -> Software._AppParams | Never: if hasattr(self, key): app: Software._Apps = getattr(self, key) else: raise KeyError return app def __setitem__(self, key: tuple[str, SoftPathGroup], **value: IdlePath | list[IdlePath]) -> None | Never: if len(value) < 1 or len(value) > 3: raise ValueError app_params: Software._SubAppParams = value if hasattr(self, key[0]): app: Software._Apps = getattr(self, key[0]) if hasattr(app, key[1]): app_child: Software._SubAppParams = getattr(app, key[1]) for k, v in app_params.items(): v = [v] if not isinstance(v, list) else v app_child[k]: IdlePath | list[IdlePath] = v setattr(app, key[1], app_child) else: raise KeyError setattr(self, key[0], app) else: raise KeyError def __delitem__(self, key: tuple[str | SoftPathGroup]) -> None | Never: if len(key) < 1 or len(key) > 3: raise KeyError if not hasattr(self, key[0]): raise KeyError if len(key) == 1: delattr(self, key[0]) elif len(key) > 1: app: Software._Apps = getattr(self, key[0]) delattr(app, key[1]) setattr(self, key[0], app) def list(self, contents: bool = False) -> tuple[str]: apps: tuple[str] | tuple[Software._Apps] = tuple( filter( lambda a: isinstance(getattr(self, a), Software._Apps), dir(self) ) ) if contents: apps = tuple( map( lambda a: getattr(self, a), apps ) ) return apps def __len__(self) -> int: apps: tuple[str] = tuple( filter( lambda a: isinstance(getattr(self, a), Software._Apps), dir(self) ) ) return len(apps)