#!/usr/bin/env python3 # -*- coding: utf-8 -*- from typing import Any, Self, Sequence, Optional from re import Match as REMatch from Utils.Check import Check from Utils.Options import Options from Utils.Patterns import RE class Common: GET_DICTIONARY_OPTIONS:Options = Options(Options.NO_OVERWRITE) GET_VALUE_OPTIONS:Options = Options(Options.ALLOW_NULLS) @classmethod def get_keys(cls:type[Self], *items:Any|None) -> list[str]: keys:list[str] = [] item:Any|None for item in items: if Check.is_key(item): item in keys or keys.append(item) elif Check.is_array(item): key:str for key in cls.get_keys(*item): key in keys or keys.append(key) return keys @classmethod def get_dictionaries(cls:type[Self], *items:Any|None) -> list[dict[str, Any|None]]: dictionaries:list[dict[str, Any|None]] = [] item:Any|None for item in items: if Check.is_dictionary(item): item in dictionaries or dictionaries.append(item) elif Check.is_array(item): dictionary:dict for dictionary in cls.get_dictionaries(*item): dictionary in dictionaries or dictionaries.append(dictionary) return dictionaries @classmethod def get_dictionary(cls:type[Self], items:Any|None, custom_options:int = 0) -> dict[str, Any|None]: dictionary:dict[str, Any|None] = {} options:Options = Options(custom_options, cls.GET_DICTIONARY_OPTIONS) if Check.is_dictionary(items): dictionary = items elif Check.is_array(items): item:Any|None for item in items: key:str value:Any|None for key, value in cls.get_dictionary(item, options).items(): if options.overwrite or key not in dictionary: dictionary[key] = value return dictionary @classmethod def get_value(cls:type[Self], keys:str|Sequence[str], inputs:dict[str, Any|None]|Sequence[Any|None], default:Optional[Any] = None, custom_options:int = 0 ) -> Any|None: options:Options = Options(custom_options, cls.GET_VALUE_OPTIONS) if len(keys := cls.get_keys(keys)): subinputs:dict[str, Any|None] for subinputs in cls.get_dictionaries(inputs): key:str for key in keys: if key in subinputs and ( options.allow_null or subinputs[key] is not None ): return subinputs[key] return default @staticmethod def get_array(value:Any|None) -> list[Any]: return ( value if isinstance(value, list) else list(value) if isinstance(value, (set, tuple)) else [value]) @staticmethod def get_strings(value:Any|None) -> list[str]: strings:list[str] = [] item:Any|None for item in Common.get_array(value): if Check.is_string(item): item in strings or strings.append(item) elif Check.is_array(item): strings.extend(Common.get_strings(item)) return strings @classmethod def string_variables(cls:type[Self], string:str, variables:dict[str, Any|None], default:Optional[str] = None ) -> str: variables = Common.get_dictionary(variables) def callback(matches:REMatch) -> str: key:str = matches.group(1) return ( str(variables[key]) if key in variables else default if default is not None else matches.group(0)) return RE.STRING_VARIABLES.sub(callback, string)