Mercurial > cgi-bin > hgweb.cgi > tincan
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)))