Mercurial > cgi-bin > hgweb.cgi > tincan
changeset 3:c6902cded64d draft
Corrections and reorg.
author | David Barts <n5jrn@me.com> |
---|---|
date | Mon, 13 May 2019 06:53:08 -0700 |
parents | ca6f8ca38cf2 |
children | 0d47859f792a |
files | pspx.html tincan.py |
diffstat | 2 files changed, 51 insertions(+), 35 deletions(-) [+] |
line wrap: on
line diff
--- a/pspx.html Sun May 12 22:51:34 2019 -0700 +++ b/pspx.html Mon May 13 06:53:08 2019 -0700 @@ -18,10 +18,9 @@ header lines may appear only once in a given file.</p> <dl> <dt><code>#errors</code></dt> - <dd>This is an error page which handles the specified HTTP error codes. - The codes are specified in numeric form, separated by whitespace. If no - error codes are specified, this page handles all possible HTTP error - codes.</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 @@ -46,7 +45,8 @@ <dd>The rest of the line is treated as a remark (comment) and is ignored.</dd> <dt><code>#template</code></dt> <dd>Ignore the body of this file and instead use the template in the body - of the specified file, which must end in <span class="kbd">.pspx</span>.</dd> + of the specified file, which must end in <span class="kbd">.pspx</span>. + Any headers in the referred template file are ignored.</dd> </dl> <p>It is possible to include whitespace and special characters in arguments to the <code>#forward</code>, <code>#python</code>, and <code>#template</code> @@ -54,7 +54,7 @@ example, <code>#python "space case.py"</code>.</p> <h3>Error Pages</h3> <p>Error pages supersede the standard Bottle error handling, and are created - by using the <code>#error</code> page header. <em>Error pages have no + by using the <code>#errors</code> page header. <em>Error pages have no associated code-behind;</em> they consist of templates only. Error page templates are provided with two variables when rendering:</p> <dl> @@ -63,7 +63,10 @@ <dt><code>request</code></dt> <dd>The <code>bottle.Request</code> object associated with this error.</dd> </dl> - <p>The behavior of specifying multiple error pages for the same error code + <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> <h2>The Body</h2> <p>The body begins with the first line that <em>does not</em> start with <code>#</code>
--- a/tincan.py Sun May 12 22:51:34 2019 -0700 +++ b/tincan.py Mon May 13 06:53:08 2019 -0700 @@ -321,7 +321,11 @@ self._template = TemplateFile(self._fspath) self._header = TemplateHeader(self._template.header) if hidden is None: + if self._header.errors is not None: + break hidden = self._header.hidden + elif self._header.errors is not None: + raise TinCanError("{0}: #forward to #errors not allowed".format(self._origin)) if self._header.forward is None: break self._redirect() @@ -331,32 +335,53 @@ return # If this is an error page, register it as such. if self._header.errors is not None: - if self._header.template is not None: - tpath = os.path.join(self._fsroot, *self._splitpath(self._header.template)) - self._template = - try: - errors = [ int(i) for i in self._header.errors.split() ] - except ValueError as e: - raise TinCanError("{0}: bad #errors line".format(self._urlpath)) from e - if not errors: - errors = range(_ERRMIN, _ERRMAX+1) - route = TinCanErrorRoute(self._tclass(source=self._template.body)) - 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._mkerror() return # this implies #hidden # Get methods for this route if self._header.methods is None: methods = [ 'GET' ] else: methods = [ i.upper() for i in self._header.methods.split() ] + if not methods: + raise TinCanError("{0}: no #methods specified".format(self._urlpath)) # Process other header entries if self._header.python is not None: if not self._header.python.endswith(_PEXTEN): raise TinCanError("{0}: #python files must end in {1}", self._urlpath, _PEXTEN) self._python = self._header.python # Obtain a class object by importing and introspecting a module. + self._getclass() + # Build body object (Chameleon template) + if self._header.template is not None: + if not self._header.template.endswith(_TEXTEN): + raise TinCanError("{0}: #template files must end in {1}", self._urlpath, _TEXTEN) + tpath = os.path.join(self._fsroot, *self._splitpath(self._header.template)) + tfile = TemplateFile(tpath) + self._body = self._tclass(source=tfile.body) + else: + self._body = self._tclass(source=self._template.body) + self._body.prepare() + # Register this thing with Bottle + print("adding route:", self._origin) # debug + self._app.route(self._origin, methods, self) + + def _splitpath(self, unsplit): + return _normpath(self._subdir, unsplit) + + def _mkerror(self): + try: + errors = [ int(i) for i in self._header.errors.split() ] + except ValueError as e: + raise TinCanError("{0}: bad #errors line".format(self._urlpath)) from e + if not errors: + errors = range(_ERRMIN, _ERRMAX+1) + route = TinCanErrorRoute(self._tclass(source=self._template.body)) + 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) + + def _getclass(self): pypath = os.path.normpath(os.path.join(self._fsroot, *self._subdir, self._python)) pycpath = pypath + 'c' try: @@ -381,20 +406,8 @@ if self._class is not None: raise TinCanError("{0}: contains multiple Page classes", pypath) self._class = v - # Build body object (Chameleon template) - if self._header.template is not None: - tpath = os.path.join(self._fsroot, *self._splitpath(self._header.template)) - tfile = TemplateFile(tpath) - self._body = self._tclass(source=tfile.body) - else: - self._body = self._tclass(source=self._template.body) - self._body.prepare() - # Register this thing with Bottle - print("adding route:", self._origin) # debug - self._app.route(self._origin, methods, self) - - def _splitpath(self, unsplit): - return _normpath(self._subdir, unsplit) + if self._class is None: + raise TinCanError("{0}: contains no Page classes", pypath) def _redirect(self): if self._header.forward in self._seen: