2023-06-10 17:39:32 +00:00
|
|
|
from datetime import datetime
|
2023-06-11 18:51:03 +00:00
|
|
|
from math import ceil
|
2023-06-12 12:32:58 +00:00
|
|
|
import os
|
2023-07-10 17:25:01 +00:00
|
|
|
from os.path import isfile, dirname
|
2024-01-27 14:05:33 +00:00
|
|
|
import traceback
|
2023-06-10 17:39:32 +00:00
|
|
|
|
2024-02-09 14:52:30 +00:00
|
|
|
class AppError(Exception):
|
|
|
|
pass
|
|
|
|
|
2023-07-10 17:25:01 +00:00
|
|
|
def open_file(fn):
|
|
|
|
d = dirname(fn)
|
|
|
|
os.makedirs(d, exist_ok=True)
|
|
|
|
if isfile(fn):
|
|
|
|
return open(fn, 'rb+')
|
2023-06-12 12:32:58 +00:00
|
|
|
else:
|
2023-07-10 17:25:01 +00:00
|
|
|
return open(fn, 'ab+')
|
|
|
|
|
2023-06-10 17:39:32 +00:00
|
|
|
def must_get(d, k):
|
|
|
|
if type(k) == str:
|
|
|
|
k = k.split('.')
|
|
|
|
part = k.pop(0)
|
|
|
|
if type(d) != dict or part not in d:
|
|
|
|
raise ValueError(part + ' not found')
|
|
|
|
val = d[part]
|
|
|
|
if len(k) == 0:
|
|
|
|
return val
|
|
|
|
else:
|
|
|
|
return must_get(val, k)
|
|
|
|
|
|
|
|
mg = must_get
|
|
|
|
|
|
|
|
def should_get(d, k, default=None):
|
|
|
|
try:
|
|
|
|
return must_get(d, k)
|
|
|
|
except ValueError:
|
|
|
|
return default
|
|
|
|
|
|
|
|
sg = should_get
|
|
|
|
|
|
|
|
def find_where_eq(l, k, v):
|
|
|
|
for i in l:
|
|
|
|
if k in i and i[k] == v:
|
|
|
|
return i
|
|
|
|
return None
|
|
|
|
|
|
|
|
def all_subclasses(cls):
|
|
|
|
return set(cls.__subclasses__()).union(
|
|
|
|
[s for c in cls.__subclasses__() for s in all_subclasses(c)])
|
|
|
|
|
|
|
|
def pprint(d, detail=2):
|
|
|
|
print(pretty(d, detail=detail))
|
|
|
|
|
|
|
|
def pretty(d, ident=0, detail=2):
|
|
|
|
if type(d) in [int, str, float, bool]:
|
|
|
|
return str(d)
|
|
|
|
if hasattr(d, 'f'):
|
|
|
|
return d.f(detail)
|
|
|
|
r = ''
|
|
|
|
idt = ' ' * ident
|
2023-07-11 20:09:57 +00:00
|
|
|
if type(d) in [list, set]:
|
2023-06-10 17:39:32 +00:00
|
|
|
r += 'lst'
|
|
|
|
for i in d:
|
|
|
|
r += '\n' + idt + pretty(i, ident + 1, detail)
|
|
|
|
elif type(d) == dict:
|
|
|
|
r += 'map'
|
|
|
|
for k,v in d.items():
|
|
|
|
r += '\n' + idt + k + ': ' + pretty(v, ident + 1, detail)
|
|
|
|
return r
|
|
|
|
|
|
|
|
def trim(s, l):
|
|
|
|
s = s[:l]
|
|
|
|
s += ' ' * (l-len(s))
|
|
|
|
return s
|
2023-06-11 18:51:03 +00:00
|
|
|
|
|
|
|
def total_pages(meta):
|
|
|
|
total = mg(meta, 'total')
|
|
|
|
limit = mg(meta, 'limit')
|
|
|
|
pages = ceil(total / limit)
|
|
|
|
return pages
|
2023-06-10 17:39:32 +00:00
|
|
|
|
|
|
|
# >>> parse_timestamp('2023-06-02T20:34:48.293Z')
|
|
|
|
# 1685738088
|
|
|
|
def parse_timestamp(ts):
|
|
|
|
return int(datetime.strptime(ts, '%Y-%m-%dT%H:%M:%S.%f%z').timestamp())
|
|
|
|
|
|
|
|
def render_timestamp(ts):
|
|
|
|
return datetime.utcfromtimestamp(ts).isoformat()
|
|
|
|
|
2024-01-27 14:05:33 +00:00
|
|
|
def fmtex(e):
|
|
|
|
return ''.join(traceback.TracebackException.from_exception(e).format())
|