NucelarMonitor/Python/Utils/Utils.py

219 lines
5.8 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Any, Self, Optional, Sequence, Callable
from re import Match as REMatch
from inspect import FrameInfo, stack as get_stack
from Utils.Patterns import RE
from json import dumps as json_encode, loads as json_decode
class Utils:
SPECIAL_REGULAR_EXPRESSION_CHARACTERS:dict[str, str] = {
"\r" : "r",
"\n" : "n",
"\t" : "t"
}
@classmethod
def get_dictionary(cls:type[Self], *items:Sequence[Any|None]) -> dict[str, Any|None]:
dictionary:dict[str, Any|None] = {}
item:Any|None
for item in items:
if isinstance(item, dict):
dictionary.update(item)
elif isinstance(item, (list, tuple)):
subitem:Any|None
for subitem in item:
dictionary.update(cls.get_dictionary(subitem))
return dictionary
@classmethod
def get_keys(cls:type[Self], *items:Sequence[Any|None]) -> list[str]:
keys:list[str] = []
item:Any|None
for item in items:
if isinstance(item, str):
RE.KEY.match(item) and keys.append(item)
elif isinstance(item, (list, tuple)):
subitem:Any|None
for subitem in item:
keys.extend(cls.get_keys(subitem))
return keys
@classmethod
def get_dictionaries(cls:type[Self], *items:Sequence[Any|None]) -> list[dict[str, Any|None]]:
dictionaries:list[dict[str, Any|None]] = []
item:Any|None
for item in items:
if isinstance(item, dict):
dictionaries.append(item)
elif isinstance(item, (list, tuple)):
subitem:Any|None
for subitem in item:
dictionaries.extend(cls.get_dictionaries(subitem))
return dictionaries
@classmethod
def get_value(cls:type[Self],
keys:str|Sequence[str],
inputs:dict[str, Any|None]|Sequence[Any|None],
default:Optional[Any] = None
) -> Any|None:
if len(cls.get_keys(keys)):
dictionary:dict[str, Any|None]
for dictionary in cls.get_dictionaries(inputs):
key:str
for key in cls.get_keys(keys):
if key in dictionary:
return dictionary[key]
return default
@staticmethod
def get_list(item:Any|None) -> list[Any|None]:
return item if isinstance(item, (list, tuple)) else [item]
@classmethod
def string_variables(cls:type[Self],
string:str,
inputs:dict[str, Any|None]|Sequence[Any|None],
default:Optional[str] = None
) -> str:
variables:dict[str, Any|None] = cls.get_dictionary(inputs)
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_VARIABLE.sub(callback, string)
@classmethod
def get_texts(cls:type[Self], *items:list[Any|None]) -> list[str]:
texts:list[str] = []
item:Any|None
for item in items:
if isinstance(item, str):
texts.append(item)
elif isinstance(item, (list, tuple)):
subitem:Any|None
for subitem in item:
texts.extend(cls.get_texts(subitem))
return texts
@staticmethod
def get_action_data(i:int = 0) -> dict[str, str|int]:
stack:FrameInfo = get_stack()[i]
return {
"file" : stack.filename,
"method" : stack.function,
"line" : stack.lineno
}
@classmethod
def to_regular_expression(cls:type[Self], string:str) -> str:
def callback(matches:REMatch) -> str:
character:str = matches.group(0)
return "\\" + (
cls.SPECIAL_REGULAR_EXPRESSION_CHARACTERS[character] if character in cls.SPECIAL_REGULAR_EXPRESSION_CHARACTERS else
character)
return RE.TO_REGULAR_EXPRESSION.sub(callback, string)
@staticmethod
def json_decode(data:str) -> Any|None:
try:
return json_decode(data)
except Exception as _:
pass
return None
@staticmethod
def json_encode(data:Sequence[Any|None]|dict[str, Any|None]) -> str|None:
try:
return json_encode(data)
except Exception as _:
pass
return None
@staticmethod
def to_snake(string:str) -> str:
def callback(matches:REMatch) -> str:
upper:str|None = matches.group(1)
return "_" + upper.lower() if upper else "_"
return RE.TO_SNAKE.sub(callback, string).lower()
@staticmethod
def get_function(string:str, _from:list[str] = []) -> Optional[Callable[[Any|None], Any|None]]:
item:Any|None
fragments:list[str] = string.split(".")
fragment:str
done:bool
for item in _from:
done = True
for fragment in fragments:
if done := hasattr(item, fragment):
item = getattr(item, fragment)
else:
break
if done and callable(item):
return item
if done := fragments[0] in globals():
item = globals()[fragments[0]]
for fragment in fragments[1:]:
if done := hasattr(item, fragment):
item = getattr(item, fragment)
else:
break
if done and callable(item):
return item
return None