import airspeed, os, html
from sanic import response
try:
from html5print import HTMLBeautifier
except ModuleNotFoundError:
pass
#import colorscheme#imported later instead to avoid problems with cyclic imports
import config
def readfile(path, binary=False):
with open(path, "rb" if binary else "r") as f:
return f.read()
#template helpers:
def escape_html(data, break_newlines=True):
if type(data) is list:
data = "\n".join(data)
if data is None:
data = ""
if break_newlines:
return html.escape(str(data)).replace("\n", "
")
else:
return html.escape(str(data))
def escape_url(data):
return "ølailsf"#todo
def strip_unit(data, unit):
if data.lower().strip().endswith(unit.lower()):
return data.strip()[:-len(unit)].strip()
return data.strip()
#decorators:
def memoize(func):#a decorator
class Memoizer(dict):
def getter(self, *args, **kwargs):
return self[(args, frozenset(kwargs.items()))]
def __missing__(self, key):
ret = self[key] = func(*key[0], **dict(key[1]))
return ret
return Memoizer().getter
def memoize_singlearg(func):#a decorator
class Memoizer(dict):
def __missing__(self, key):
ret = self[key] = func(key)
return ret
return Memoizer().__getitem__
def wrap_output(type):#decorator with parameters
def decorator(func):#decorator
def new_func(*args, **kwargs):
return type(func(*args, **kwargs))
return new_func
return decorator
def call(func):#decorator
return func()
#types:
class Model:
def __setattr__(self, name, value):
if not hasattr(self, name):
raise Exception(f"{self.__class__.__name__} has no attribute {name!r}")
super(Model, self).__setattr__(name, value)
def __repr__(self):
return self.__class__.__name__ + "(%s)" % \
", ".join(f"{i}={getattr(self, i)!r}" for i in dir(self) if "_" not in (i[0], i[-1]))
__str__ = __repr__
#fileloader:
class VelocityFileLoader:
_cache = {}#static cache, shared between instances
def get_file(self, filename):
file = readfile(filename)
if filename[-4:] == ".svg":
pass#file = file.replace("fill:#", "")#a nasty hack
return file
def load_text(self, name):
if name[-4:] == ".svg":
filename = os.path.join(config.svgdir, name)
else:
filename = os.path.join(config.resourcedir, name)
if config.cache:
if filename not in self.memory:
self._cache[filename] = self.get_file(filename)
return self._cache[filename]
return self.get_file(filename)
#decorators with parameters:
def withResource(path, binary=False):
if config.cache:
data = readfile(os.path.join(config.resourcedir, path), binary)
def decorator(func):
def newfunc(*args, **kwargs):
if not config.cache:
content = readfile(os.path.join(config.resourcedir, path), binary)
else:
content = data
return func(*args, content, **kwargs)
return newfunc
return decorator
def mergeTemplate(path):
import colorscheme
filename = os.path.join(config.resourcedir, path)
if config.cache:
template = airspeed.Template(readfile(filename), filename)
def decorator(func):
async def newfunc(*args, **kwargs):
if config.cache:
tem = template
else:
tem = airspeed.Template(readfile(filename), filename)
objects = await func(*args, **kwargs)
if type(objects) is response.HTTPResponse:
return objects
objects.update({
"strip_unit": strip_unit,
"escape_html": escape_html,
"escape_url": escape_url,
"get_colorscheme":colorscheme.get})
if config.prettifyHTML:
return response.html(HTMLBeautifier.beautify(
tem.merge(objects, loader=VelocityFileLoader()),
indent = 4))#.replace("/>", ">")
else:
return response.html(tem.merge(objects, loader=VelocityFileLoader()))
return newfunc
return decorator