# HG changeset patch # User David Barts # Date 1557784024 25200 # Node ID 31bb8400e6e3dd7dacf0a976140501f78f729d78 # Parent 0d47859f792a86d848ee4eca6c508dab69f9c3b8 Add #end header, fix #errors. diff -r 0d47859f792a -r 31bb8400e6e3 pspx.html --- 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 #rem header, all header lines may appear only once in a given file.

+
#end
+
Marks the last line of the headers. Needed only for templating + languages where lines often start with #, such + as Cheetah.
+

+
#errors
-
Ignore other headers and make this is an error page which handles - the specified HTTP error codes. See the subsection on error pages below. -
+
Ignore other headers and make this is an error page which handles the + specified HTTP error codes. See the subsection on error pages below.
#forward
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 @@
This is a hidden page; do not create a route for it. The page can only be displayed by a forward.
#methods
-
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 #methods GET.
+
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 #methods GET.
#python
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; they consist of templates only. Error page templates are provided with two variables when rendering:

-
e
+
error
The bottle.HTTPError object associated with this error.
request
The bottle.Request object associated with this error.

The #errors 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.

+ (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.

The Body

The body begins with the first line that does not start with # and has the exact same syntax that the templates are in for this webapp. diff -r 0d47859f792a -r 31bb8400e6e3 tincan.py --- 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)))