Source code for sni.utils
"""
Various utilities
"""
from importlib import import_module
from typing import Any, Callable, Tuple
import logging
import random
import string
from datetime import datetime, timedelta
from pytz import utc
MINUTE = 60
HOUR = 60 * MINUTE
DAY = 24 * HOUR
# pylint: disable=dangerous-default-value
[docs]def catch_all(
function: Callable,
error_message: str,
*,
args: Tuple[Any, ...] = tuple(),
kwargs: dict = {},
) -> None:
"""
Calls a function but catches all the exceptions. If any were raised, logs
an error message, followed by the string representation of the exception.
"""
try:
function(*args, **kwargs)
except Exception as error:
logging.error("%s: %s", error_message, str(error))
[docs]def catches_all(error_message: str = "Error") -> Callable:
"""
Decorator version of :meth:`sni.utils.catch_all`.
"""
def decorator(function: Callable) -> Callable:
def wrapper(*args, **kwargs) -> None:
catch_all(function, error_message, args=args, kwargs=kwargs)
return wrapper
return decorator
# pylint: disable=dangerous-default-value
[docs]async def catch_all_async(
function: Callable,
error_message: str,
*,
args: Tuple[Any, ...] = tuple(),
kwargs: dict = {},
) -> None:
"""
Calls a function but catches all the exceptions. If any were raised, logs
an error message, followed by the string representation of the exception.
"""
try:
await function(*args, **kwargs)
except Exception as error:
logging.error("%s: %s", error_message, str(error))
[docs]def from_timestamp(timestamp: int) -> datetime:
"""
Returns a UTC datetime from a UNIX timestamp.
"""
return datetime.utcfromtimestamp(timestamp)
[docs]def now() -> datetime:
"""
Returns the current UTC datetime.
"""
return datetime.now(utc)
[docs]def now_plus(**kwargs) -> datetime:
"""
Returns the current UTC datetime plus a specified timedelta.
See also:
`datetime.timedelta <https://docs.python.org/3/library/datetime.html?highlight=timedelta#datetime.timedelta>`_
"""
return now() + timedelta(**kwargs)
[docs]def object_from_name(name: str) -> Any:
"""
Returns a callable from its name, e.g. ``sni.esi.jobs:refresh_tokens``.
"""
try:
module_name, function_name = name.split(":")
module = import_module(module_name)
return getattr(module, function_name)
except Exception as error:
raise ValueError(f'Could not load object "{name}": {str(error)}')
[docs]def random_code(length: int) -> str:
"""
Returns a random string made of digits, lowercase letters, and uppercase
letters, of a given length.
Warning:
Not cryptographically secure.
"""
return "".join(
[
random.choice(string.ascii_letters + string.digits) # nosec
for _ in range(length)
]
)