CXCV/Python/Utils/Utils.py

165 lines
4.8 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Any, Self, Optional
from inspect import stack as get_stack, FrameInfo
from traceback import format_stack as trace_format_stack, extract_tb as extract_traceback
from json import loads as json_decode, dumps as json_encode
from re import Match as REMatch
from Utils.Patterns import RE
class Utils:
@classmethod
def get_keys(cls:type[Self], *items:list[Any|None]) -> list[str]:
keys:list[str] = []
item:Any|None
for item in items:
if isinstance(item, (list, tuple)):
keys += cls.get_keys(*item)
elif isinstance(item, str) and RE.KEY.match(item):
keys += [item]
return keys
@classmethod
def get_dictionaries(cls:type[Self], *items:list[Any|None]) -> list[dict[str, Any|None]]:
dictionaries:list[dict[str, Any|None]] = []
item:Any|None
for item in items:
if isinstance(item, (list, tuple)):
dictionaries += cls.get_dictionaries(*item)
elif isinstance(item, dict):
dictionaries += [item]
return dictionaries
@classmethod
def get_dictionary(cls:type[Self], *items:list[Any|None]) -> dict[str, Any|None]:
dictionary:dict[str, Any|None] = {}
for item in items:
if isinstance(item, (list, tuple)):
dictionary = {**cls.get_dictionary(*item), **dictionary}
elif isinstance(item, dict):
dictionary = {**item, **dictionary}
return dictionary
@classmethod
def get_value(cls:type[Self],
keys:str|list[str]|tuple[str, ...],
inputs:dict[str, Any|None]|list[Any|None]|tuple[Any|None, ...],
default:Optional[Any] = None
) -> Any|None:
if len(keys := cls.get_keys(keys)):
subinputs:dict[str, Any|None]
for subinputs in cls.get_dictionaries(inputs):
for key in keys:
if key in subinputs:
return subinputs[key]
return default
@classmethod
def get_strings(cls:type[Self], *items:list[Any|None]) -> list[str]:
strings:list[str] = []
item:Any|None
for item in items:
if isinstance(item, (list, tuple)):
strings += cls.get_strings(*item)
elif isinstance(item, str):
strings += [item]
return strings
@classmethod
def get_keys(cls:type[Self], *items:list[Any|None]) -> list[str]:
keys:list[str] = []
item:Any|None
for item in items:
if isinstance(item, (list, tuple)):
keys += cls.get_keys(*item)
elif isinstance(item, str) and RE.KEY.match(item):
keys += [item]
return keys
@classmethod
def string_variables(cls:type[Self],
string:str,
variables:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None, ...]] = None,
default:str|None = None
) -> str:
variables = cls.get_dictionary(variables)
def callback(matches:REMatch) -> str:
key:str = matches.group(1)
if key in variables:
return str(variables[key])
return matches.group(0) if default is None else default
return RE.STRING_VARIABLE.sub(callback, string)
@staticmethod
def json_decode(data:str) -> dict[str, Any|None]|tuple[Any|None, ...]|list[Any|None]|None:
try:
return json_decode(data)
except Exception as exception:
pass
return None
@staticmethod
def json_encode(data:dict[str, Any|None]|tuple[Any|None, ...]|list[Any|None]|None) -> str|None:
try:
return json_encode(data)
except Exception as exception:
pass
return None
@staticmethod
def get_from(
item:list[Any|None]|tuple[Any|None, ...],
indexes:int|list[int]|tuple[int, ...],
default:Optional[Any] = None
) -> Any|None:
l:int = len(item)
i:int
for i in indexes if isinstance(indexes, (list, tuple)) else (indexes,):
if i >= l:
break
if item[i] is not None:
return item[i]
return default
@staticmethod
def get_action_data(i:int = 0) -> dict[str, str|int]:
stack:FrameInfo = get_stack()[1 + i]
return {
"file" : stack.filename,
"method" : stack.function,
"line" : stack.lineno
}
@staticmethod
def get_trace(exception:Optional[Exception] = None) -> list[str]:
return trace_format_stack()[:-2] + (
extract_traceback(exception.__traceback__).format() if exception else
[])