177 lines
5.8 KiB
Python
177 lines
5.8 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from Utils.Check import Check
|
|
from typing import Any, Self, Optional
|
|
from Utils.Patterns import RE
|
|
from re import Match as REMatch
|
|
from inspect import stack as get_stack
|
|
from inspect import FrameInfo
|
|
from json import loads as json_decode
|
|
from json import dumps as json_encode
|
|
from random import random as math_random
|
|
from base64 import b64decode as base64_decode
|
|
from base64 import b64encode as base64_encode
|
|
|
|
class Utils:
|
|
|
|
@classmethod
|
|
def get_keys(cls:type[Self], *items:list[Any|None]) -> list[str]:
|
|
return [key for item in items for key in (
|
|
(item,) if Check.is_key(item) else
|
|
cls.get_keys(*item) if Check.is_array(item) else
|
|
tuple())]
|
|
|
|
@classmethod
|
|
def get_dictionaries(cls:type[Self], *items:list[Any|None]) -> list[dict[str, Any|None]]:
|
|
return [dictionary for item in items for dictionary in (
|
|
(item,) if Check.is_dictionary(item) else
|
|
cls.get_dictionaries(*item) if Check.is_array(item) else
|
|
tuple())]
|
|
|
|
@classmethod
|
|
def get_dictionary(cls:type[Self], *items:list[Any|None]) -> dict[str, Any|None]:
|
|
return {key : value for item in items for key, value in (
|
|
item if Check.is_dictionary(item) else
|
|
cls.get_dictionary(*item) if Check.is_array(item) else
|
|
{}).items()}
|
|
|
|
@classmethod
|
|
def get_values(cls:type[Self], keys:str|list|tuple, inputs:dict[str, Any|None]|list[Any|None]|tuple[Any|None], _default:Optional[Any] = None) -> Any|None:
|
|
|
|
keys = cls.get_keys(keys)
|
|
|
|
if len(keys):
|
|
|
|
subinputs:dict[str, Any|None]
|
|
|
|
for subinputs in cls.get_dictionaries(inputs):
|
|
|
|
key:str
|
|
|
|
for key in keys:
|
|
if key in subinputs:
|
|
return subinputs[key]
|
|
return _default
|
|
|
|
@classmethod
|
|
def string_variables(cls:type[Self], string:str, variables:dict[str, Any|None], _default:Optional[str] = None) -> str|None:
|
|
|
|
variables = cls.get_dictionary(variables)
|
|
|
|
def callback(matches:REMatch) -> str:
|
|
|
|
key:str = matches.group(1)
|
|
|
|
return (
|
|
str(variables[key]) if key in variables else
|
|
str(_default) if _default is not None else
|
|
matches.group(0))
|
|
|
|
return RE.STRING_VARIABLES.sub(callback, str(string))
|
|
|
|
@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
|
|
}
|
|
|
|
@classmethod
|
|
def get_strings(cls:type[Self], *items:list[Any|None]) -> list[str]:
|
|
return [string for item in items for string in (
|
|
cls.get_strings(*item) if Check.is_array(item) else (item,)
|
|
) if Check.is_string(string)]
|
|
|
|
@staticmethod
|
|
def json_encode(data:dict[str, Any|None]|list[Any|None]|tuple[Any|None]) -> str|None:
|
|
try:
|
|
return json_encode(data, ensure_ascii=False)
|
|
except Exception as exception:
|
|
pass
|
|
return None
|
|
|
|
@staticmethod
|
|
def json_decode(data:str) -> dict[str, Any|None]|list[Any|None]|tuple[Any|None]|None:
|
|
try:
|
|
return json_decode(data)
|
|
except Exception as exception:
|
|
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 recursive(data:str, callback:Any) -> str:
|
|
|
|
cache:str = data
|
|
|
|
while True:
|
|
data = cache
|
|
cache = callback(cache)
|
|
if data == cache:
|
|
break
|
|
|
|
return cache
|
|
|
|
@staticmethod
|
|
def get_array(item:Any|None) -> list[Any|None]:
|
|
return item if Check.is_array(item) else [item]
|
|
|
|
@staticmethod
|
|
def get_random(_from:Optional[int] = None, _to:Optional[int] = None) -> Any|None:
|
|
return (
|
|
math_random() if _from is None else
|
|
_from[int(math_random() * len(_from))] if Check.is_array(_from) else
|
|
(
|
|
int(math_random() * _from) if _to is None else
|
|
int(math_random() * (_to - _from) + _from) if Check.is_integer(_to) else
|
|
math_random() * (_to - float(_from)) + float(_from) if Check.is_float(_to) else
|
|
None) if Check.is_integer(_from) else
|
|
(
|
|
math_random() * _from if _to is None else
|
|
math_random() * (float(_to) - _from) + _from if Check.is_number(_to) else
|
|
None) if Check.is_float(_from) else
|
|
None)
|
|
|
|
@classmethod
|
|
def randomize_array(cls:type[Self], items:list[Any|None]) -> None:
|
|
|
|
l:int = len(items)
|
|
|
|
for i in range(l):
|
|
|
|
j:int = cls.get_random(l)
|
|
|
|
if i != j:
|
|
items[i], items[j] = items[j], items[i]
|
|
|
|
@staticmethod
|
|
def base64_encode(data:str|bytes, encoding:str = "utf-8") -> str|None:
|
|
try:
|
|
return base64_encode(data.encode(encoding) if Check.is_string(data) else data).decode(encoding)
|
|
except Exception as exception:
|
|
pass
|
|
return None
|
|
|
|
@staticmethod
|
|
def base64_decode(data:str|bytes, encoding:str = "utf-8", is_string:bool = True) -> str|bytes|None:
|
|
try:
|
|
decoded:bytes = base64_decode(data.encode(encoding) if Check.is_string(data) else data)
|
|
return decoded.decode(encoding) if is_string else decoded
|
|
except Exception as exception:
|
|
pass
|
|
return None |