changeset 23:e8b6ee7e5b6b draft

Well, *that* attempt at includes didn't work. Revert.
author David Barts <n5jrn@me.com>
date Tue, 21 May 2019 18:01:44 -0700
parents f6a1492fe56e
children 34d3cfcd37ef ee19984ba31d
files tincan.py
diffstat 1 files changed, 15 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- 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