# HG changeset patch # User David Barts # Date 1558486904 25200 # Node ID e8b6ee7e5b6b5bdb09ee418590c95e47f9e70823 # Parent f6a1492fe56e6aaf026ee56e5d8e5b2503fba4c6 Well, *that* attempt at includes didn't work. Revert. diff -r f6a1492fe56e -r e8b6ee7e5b6b tincan.py --- a/tincan.py Tue May 21 16:01:53 2019 -0700 +++ b/tincan.py Tue May 21 18:01:44 2019 -0700 @@ -18,7 +18,6 @@ import traceback import urllib -from chameleon import PageTemplate, PageTemplateFile import bottle # E x c e p t i o n s @@ -167,15 +166,13 @@ # Update this object setattr(self, name, param) -# C h a m e l e o n ( B o t t l e ) +# C h a m e l e o n # -# Support for Chameleon templates (the kind TinCan uses by default). This -# allows the usage of Chameleon with Bottle itself. It is here as a -# convenience for those using Bottle routes as well as TinCan webapps; -# this is NOT how Tincan uses Chameleon +# Support for Chameleon templates (the kind TinCan uses by default). class ChameleonTemplate(bottle.BaseTemplate): def prepare(self, **options): + from chameleon import PageTemplate, PageTemplateFile if self.source: self.tpl = PageTemplate(self.source, encoding=self.encoding, **options) @@ -193,58 +190,6 @@ chameleon_template = functools.partial(bottle.template, template_adapter=ChameleonTemplate) chameleon_view = functools.partial(bottle.view, template_adapter=ChameleonTemplate) -# C h a m e l e o n ( T i n c a n ) -# -# How we use Chameleon ourselves. Everything is loaded as a string, and we -# provide convenience routines to load other templates. - -class TinCanChameleon(PageTemplate): - """ - Basically, a standard PageTemplate with load and lload functionality. - """ - def __init__(self, body, base=None, subdir=None, **config): - super(TinCanChameleon, self).__init__(body, **config) - if base is not None: - encoding = config.get("encoding", "utf-8") - if subdir is not None: - self.expression_types['load'] = \ - _LoaderFactory(base, subdir, encoding) - self.expression_types['lload'] = \ - _LoaderFactory(os.path.join(base,_WINF,"tlib"), [], encoding) - -class _LoaderFactory(object): - """ - One of two helper classes for the above. - """ - def __init__(self, base, subdir, encoding): - self.base = base - self.subdir = subdir - self.encoding = encoding - - def __call__(self, string): - return _Loader(self, string) - -class _Loader(object): - """ - Two of two helper classes for the above. - """ - def __init__(self, based_on, string): - if not (string.endswith(".pspx") or string.endswith(".pt")): - raise ValueError("loaded templates must end in .pspx or .pt") - self.path = string - self.params = based_on - - def __call__(self, target, engine): - try: - normalized = _normpath(self.params.subdir, self.path) - except IndexError: - raise ValueError("invalid path: {0!s}".format(self.path)) - npath = os.path.join(self.params.base, *normalized) - with open(npath, "r", encoding=self.params.encoding) as fp: - contents = fp.read() - value = ast.Str(contents) - return [ast.Assign(targets=[target], value=value)] - # U t i l i t i e s def _normpath(base, unsplit): @@ -382,6 +327,7 @@ """ def __init__(self, template, klass): self._template = template + self._template.prepare() self._class = klass def __call__(self, e): @@ -389,7 +335,7 @@ try: obj = self._class(bottle.request, e) obj.handle() - return self._template.render(**obj.export()).lstrip('\n') + return self._template.render(obj.export()).lstrip('\n') except bottle.HTTPResponse as e: return e except Exception as e: @@ -415,6 +361,7 @@ self._origin = self._urlpath self._subdir = subdir self._seen = set() + self._tclass = launcher.tclass self._app = launcher.app def launch(self): @@ -470,15 +417,10 @@ raise TinCanError("{0}: invalid #template: {1!s}".format(self._urlpath, e)) from e except IndexError as e: raise TinCanError("{0}: invalid #template".format(self._urlpath)) from e - try: - self._body = TinCanChameleon(tfile.body, base=self._fsroot, subdir=self._subdir) - except Exception as e: - raise TinCanError("{0}: template error: {1!s}".format(self._urlpath, e)) from e + self._body = self._tclass(source=tfile.body) else: - try: - self._body = TinCanChameleon(self._template.body, self._fsroot, subdir=self._subdir) - except Exception as e: - raise TinCanError("{0}: template error: {1!s}".format(self._urlpath, e)) from e + self._body = self._tclass(source=self._template.body) + self._body.prepare() # If this is an #errors page, register it as such. if oheader.errors is not None: self._mkerror(oheader.errors) @@ -504,11 +446,7 @@ raise TinCanError("{0}: bad #errors line".format(self._urlpath)) from e if not errors: errors = range(_ERRMIN, _ERRMAX+1) - try: - template = TinCanChameleon(self._template.body, base=self._fsroot, subdir=self._subdir) - except Exception as e: - raise TinCanError("{0}: template error: {1!s}".format(self._urlpath, e)) from e - route = _TinCanErrorRoute(template, self._class) + route = _TinCanErrorRoute(self._tclass(source=self._template.body), self._class) for error in errors: if error < _ERRMIN or error > _ERRMAX: raise TinCanError("{0}: bad #errors code".format(self._urlpath)) @@ -621,7 +559,7 @@ try: obj = self._class(bottle.request, bottle.response) obj.handle() - return self._body.render(**obj.export()).lstrip('\n') + return self._body.render(obj.export()).lstrip('\n') except ForwardException as fwd: target = fwd.target except bottle.HTTPResponse as e: @@ -671,12 +609,13 @@ """ Helper class for launching webapps. """ - def __init__(self, fsroot, urlroot, logger): + def __init__(self, fsroot, urlroot, tclass, logger): """ Lightweight constructor. The real action happens in .launch() below. """ self.fsroot = fsroot self.urlroot = urlroot + self.tclass = tclass self.logger = logger self.app = None self.errors = 0 @@ -741,14 +680,14 @@ sys.stderr.write(message) sys.stderr.write('\n') -def launch(fsroot=None, urlroot='/', logger=_logger): +def launch(fsroot=None, urlroot='/', tclass=ChameleonTemplate, logger=_logger): """ Launch and return a TinCan webapp. Does not run the app; it is the caller's responsibility to call app.run() """ if fsroot is None: fsroot = os.getcwd() - launcher = _Launcher(fsroot, urlroot, logger) + launcher = _Launcher(fsroot, urlroot, tclass, logger) # launcher.debug = True launcher.launch() return launcher.app, launcher.errors