changeset 5:31bb8400e6e3 draft

Add #end header, fix #errors.
author David Barts <n5jrn@me.com>
date Mon, 13 May 2019 14:47:04 -0700
parents 0d47859f792a
children a3823da7bb45
files pspx.html tincan.py
diffstat 2 files changed, 32 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/pspx.html	Mon May 13 12:38:26 2019 -0700
+++ b/pspx.html	Mon May 13 14:47:04 2019 -0700
@@ -17,10 +17,15 @@
       (#) character. With the exception of the <code>#rem </code>header, all
       header lines may appear only once in a given file.</p>
     <dl>
+      <dt><code>#end</code></dt>
+      <dd>Marks the last line of the headers. Needed only for templating
+        languages where lines often start with <span class="kbd">#</span>, such
+        as Cheetah.</dd>
+      <dd> <br>
+      </dd>
       <dt><code>#errors</code></dt>
-      <dd>Ignore other headers and make this is an error page which handles
-        the specified HTTP error codes. See the subsection on error pages below.
-      </dd>
+      <dd>Ignore other headers and make this is an error page which handles the
+        specified HTTP error codes. See the subsection on error pages below. </dd>
       <dt><code>#forward</code></dt>
       <dd>Ignore everything else in this template (and any code-behind
         associated with it), using the specified route to serve it instead. The
@@ -34,9 +39,9 @@
       <dd>This is a hidden page; do not create a route for it. The page can only
         be displayed by a forward.</dd>
       <dt><code>#methods</code></dt>
-      <dd>A list of HTTP request methods, separated by whitespace, follows. The route will
-        allow all specified methods. Not specifying this line is equivalent to
-        specifying <code>#methods GET</code>.</dd>
+      <dd>A list of HTTP request methods, separated by whitespace, follows. The
+        route will allow all specified methods. Not specifying this line is
+        equivalent to specifying <code>#methods GET</code>.</dd>
       <dt><code>#python</code></dt>
       <dd>What follows is the name of the Python file containing the code-behind
         for this route. If not specified, the code-behind will be in a file with
@@ -58,16 +63,16 @@
         associated code-behind;</em> they consist of templates only. Error page
       templates are provided with two variables when rendering:</p>
     <dl>
-      <dt><code>e</code></dt>
+      <dt><code>error</code></dt>
       <dd>The <code>bottle.HTTPError</code> object associated with this error.</dd>
       <dt><code>request</code></dt>
       <dd>The <code>bottle.Request</code> object associated with this error.</dd>
     </dl>
     <p>The <code>#errors</code> directive takes a list of numeric error codes
-    (values from 400 to 599 are allowed); the page is created to handle the
-    specified errors. If no error codes are specified, the page will handle all
-    errors. The behavior of specifying multiple error pages for the same error code
-    is undefined; doing so is best avoided.</p>
+      (values from 400 to 599 are allowed); the page is created to handle the
+      specified errors. If no error codes are specified, the page will handle
+      all errors. The behavior of specifying multiple error pages for the same
+      error code is undefined; doing so is best avoided.</p>
     <h2>The Body</h2>
     <p>The body begins with the first line that <em>does not</em> start with <code>#</code>
       and has the exact same syntax that the templates are in for this webapp.
--- a/tincan.py	Mon May 13 12:38:26 2019 -0700
+++ b/tincan.py	Mon May 13 14:47:04 2019 -0700
@@ -14,6 +14,7 @@
 import io
 import py_compile
 from stat import S_ISDIR, S_ISREG
+from string import whitespace
 
 import bottle
 
@@ -69,6 +70,10 @@
     line numbering when processing the body. The added newlines are normally
     stripped out before the rendered page is sent back to the client.
     """
+    _END = "#end"
+    _LEND = len(_END)
+    _WS = set(whitespace)
+
     def __init__(self, raw, encoding='utf-8'):
         if isinstance(raw, io.TextIOBase):
             self._do_init(raw)
@@ -95,6 +100,8 @@
             self._state = self._body
             self._state(line)
             return
+        if line.startswith(self._END) and (len(line) == self._LEND or line[self._LEND] in self._WS):
+            self._state = self._body
         self._hbuf.append(line)
         self._bbuf.append("\n")
 
@@ -129,21 +136,26 @@
             try:
                 rna, rpa = line.split(maxsplit=1)
             except ValueError:
-                raise TemplateHeaderException("Missing parameter.", count)
+                rna = line.rstrip()
+                rpa = None
             # Get name, ignoring remarks.
             name = rna[1:]
             if name == "rem":
                 continue
+            if name == "end":
+                break
             if name not in nameset:
                 raise TemplateHeaderException("Invalid directive: {0!r}".format(rna), count)
             if name in seen:
                 raise TemplateHeaderException("Duplicate {0!r} directive.".format(rna), count)
             seen.add(name)
             # Flags
-            if name in self._FLAGS:
+            if name in self._FNAMES:
                 setattr(self, name, True)
                 continue
             # Get parameter
+            if rpa is None:
+                raise TemplateHeaderException("Missing parameter.", count)
             param = rpa.strip()
             for i in [ "'", '"']:
                 if param.startswith(i) and param.endswith(i):
@@ -294,7 +306,7 @@
         self._template.prepare()
 
     def __call__(self, e):
-        return self._template.render(e=e, request=bottle.request).lstrip('\n')
+        return self._template.render(error=e, request=bottle.request).lstrip('\n')
 
 class _TinCanRoute(object):
     """
@@ -384,7 +396,7 @@
         for error in errors:
             if error < _ERRMIN or error > _ERRMAX:
                 raise TinCanError("{0}: bad #errors code".format(self._urlpath))
-            self._app.error(code=error, callback=route)
+            self._app.error_handler[error] = route  # XXX
 
     def _getclass(self):
         pypath = os.path.normpath(os.path.join(self._fsroot, *self._splitpath(self._python)))