165 lines
4.8 KiB
Python
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
|
|
[]) |