modular-service-cli/modular_service_cli/service/utils.py (64 lines of code) (raw):
import base64
import json
import time
from typing import Callable, TypeVar
import urllib.error
import urllib.request
from urllib3.exceptions import LocationParseError
from urllib3.util import parse_url
def urljoin(*args: str) -> str:
"""
This method somehow differs from urllib.parse.urljoin. See:
>>> urljoin('one', 'two', 'three')
'one/two/three'
>>> urljoin('one/', '/two/', '/three/')
'one/two/three'
>>> urljoin('https://example.com/', '/prefix', 'path/to/service')
'https://example.com/prefix/path/to/service'
:param args: list of string
:return:
"""
return '/'.join(map(lambda x: str(x).strip('/'), args))
def sifted(data: dict) -> dict:
"""
>>> sifted({'k': 'value', 'k1': None, 'k2': '', 'k3': 0, 'k4': False})
{'k': 'value', 'k3': 0, 'k4': False}
:param data:
:return:
"""
return {k: v for k, v in data.items() if isinstance(v, (bool, int)) or v}
def validate_api_link(url: str) -> str | None:
url = url.lstrip()
if "://" in url and not url.lower().startswith("http"):
return 'Invalid API link: not supported scheme'
try:
scheme, auth, host, port, path, query, fragment = parse_url(url)
except LocationParseError as e:
return 'Invalid API link'
if not scheme:
return 'Invalid API link: missing scheme'
if not host:
return 'Invalid API link: missing host'
try:
req = urllib.request.Request(url)
urllib.request.urlopen(req)
except urllib.error.HTTPError as e:
pass
except urllib.error.URLError as e:
return 'Invalid API link: cannot make a request'
RT = TypeVar('RT') # return type
ET = TypeVar('ET', bound=Exception) # exception type
def catch(func: Callable[[], RT], exception: type[ET] = Exception
) -> tuple[RT | None, ET | None]:
"""
Calls the provided function and catches the desired exception.
Seems useful to me :) ?
:param func:
:param exception:
:return:
"""
try:
return func(), None
except exception as e:
return None, e
class JWTToken:
"""
A simple wrapper over jwt token
"""
EXP_THRESHOLD = 300 # in seconds
__slots__ = '_token', '_exp_threshold'
def __init__(self, token: str, exp_threshold: int = EXP_THRESHOLD):
self._token = token
self._exp_threshold = exp_threshold
@property
def raw(self) -> str:
return self._token
@property
def payload(self) -> dict | None:
try:
return json.loads(
base64.b64decode(self._token.split('.')[1] + '==').decode()
)
except Exception:
return
def is_expired(self) -> bool:
p = self.payload
if not p:
return True
exp = p.get('exp')
if not exp:
return False
return exp < time.time() + self._exp_threshold