izzylib/IzzyLib/template.py
2021-03-02 12:13:18 -05:00

127 lines
3.2 KiB
Python

'''functions for web template management and rendering'''
import codecs, traceback, os, json, xml
from os import listdir, makedirs
from os.path import isfile, isdir, getmtime, abspath
from jinja2 import Environment, FileSystemLoader, ChoiceLoader, select_autoescape, Markup
from hamlish_jinja import HamlishExtension
from xml.dom import minidom
try:
from sanic import response as Response
except ModuleNotFoundError:
Response = None
from . import logging
from .color import *
from .misc import Path, DotDict
class Template(Environment):
def __init__(self, search=[], global_vars={}, context=None, autoescape=True):
self.autoescape = autoescape
self.search = []
self.func_context = context
for path in search:
self.__add_search_path(path)
super().__init__(
loader=ChoiceLoader([FileSystemLoader(path) for path in self.search]),
extensions=[HamlishExtension],
autoescape=self.autoescape,
lstrip_blocks=True,
trim_blocks=True
)
self.hamlish_file_extensions=('.haml',)
self.hamlish_enable_div_shortcut=True
self.hamlish_mode = 'indented'
self.globals.update({
'markup': Markup,
'cleanhtml': lambda text: ''.join(xml.etree.ElementTree.fromstring(text).itertext()),
'lighten': lighten,
'darken': darken,
'saturate': saturate,
'desaturate': desaturate,
'rgba': rgba
})
self.globals.update(global_vars)
def __add_search_path(self, path):
tpl_path = Path(path)
if not tpl_path.exists():
raise FileNotFoundError('Cannot find search path:', tpl_path.str())
if tpl_path.str() not in self.search:
self.search.append(tpl_path.str())
def addEnv(self, k, v):
self.globals[k] = v
def delEnv(self, var):
if not self.globals.get(var):
raise ValueError(f'"{var}" not in global variables')
del self.var[var]
def updateEnv(self, data):
if not isinstance(data, dict):
raise ValueError(f'Environment data not a dict')
self.globals.update(data)
def addFilter(self, funct, name=None):
name = funct.__name__ if not name else name
self.filters[name] = funct
def delFilter(self, name):
if not self.filters.get(name):
raise valueError(f'"{name}" not in global filters')
del self.filters[name]
def updateFilter(self, data):
if not isinstance(context, dict):
raise ValueError(f'Filter data not a dict')
self.filters.update(data)
def render(self, tplfile, request=None, context={}, headers={}, cookies={}, pprint=False, **kwargs):
if not isinstance(context, dict):
raise TypeError(f'context for {tplfile} not a dict: {type(context)} {context}')
context['request'] = request if request else {'headers': headers, 'cookies': cookies}
if self.func_context:
context.update(self.func_context(DotDict(context), DotDict(self.globals)))
result = self.get_template(tplfile).render(context)
if pprint and any(map(tplfile.endswith, ['haml', 'html', 'xml'])):
return minidom.parseString(result).toprettyxml(indent=" ")
else:
return result
def response(self, request, tpl, ctype='text/html', status=200, **kwargs):
if not Response:
raise ModuleNotFoundError('Sanic is not installed')
html = self.render(tpl, request=request, **kwargs)
return Response.HTTPResponse(body=html, status=status, content_type=ctype, headers=kwargs.get('headers', {}))