# HG changeset patch
# User David Barts #python
and/or #template
header
- directives will of course change this default association.
Pretty much anything can be in the code-behind files, with one restriction. There must be one and only one instance of a subclass of either Page (normal pages) or ErrorPage (error @@ -42,6 +42,21 @@ method; the default behavior as described in the Default Template Variables section of the template documentation is normally sufficient.
+These contain the code-behind for normal pages. When the handle + method begins executing, they contain two instance variables: request + (a bottle.Request object) and response (a bottle.Response + object).
+These contain the code-behind for error pages. When the handle + method begins executing, they contain two instance variables: request + (a bottle.Request object) and error (a bottle.HTTPError + object).
+There is no separate standard instance variable in either Page + or ErrorPage that provides such, because it is available via + request.app. See the Bottle documentation for more + information.
If you define a template with no code-behind file, TinCan will use either Page or ErrorPage as appropriate, which will diff -r 84998cd4e123 -r 8037bad7d5a8 pspx.html --- a/pspx.html Mon May 13 21:24:48 2019 -0700 +++ b/pspx.html Wed May 15 00:00:45 2019 -0700 @@ -18,8 +18,10 @@ header lines may appear only once in a given file.
#end
#errors
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.
- By default, Chameleon templates are used. Cheetah, Jinja2, Mako, and
- Bottle SimpleTemplate templates are also supported, provided the webapp
- was launched to use them. (Only one template style per webapp is
+ (or the first line after the #end
directive, whichever comes
+ first) and has the exact same syntax that the templates are in for this
+ webapp. By default, Chameleon templates are used. Cheetah, Jinja2, Mako,
+ and Bottle SimpleTemplate templates are also supported, provided the
+ webapp was launched to use them. (Only one template style per webapp is
supported.)
In order to make line numbers match file line numbers for reported errors, the template engine will be passed a blank line for each header diff -r 84998cd4e123 -r 8037bad7d5a8 tincan.py --- a/tincan.py Mon May 13 21:24:48 2019 -0700 +++ b/tincan.py Wed May 15 00:00:45 2019 -0700 @@ -250,7 +250,7 @@ class BasePage(object): """ - The parent class of both error and normal pages. + The parent class of both error and normal pages' code-behind. """ def handle(self): """ @@ -277,6 +277,9 @@ return ret class Page(BasePage): + """ + The code-behind for a normal page. + """ # Non-private things we refuse to export anyhow. _HIDDEN = set([ "request", "response" ]) @@ -326,6 +329,7 @@ self._class = klass def __call__(self, e): + bottle.request.environ[_FTYPE] = True obj = self._class(bottle.request, e) obj.handle() return self._template.render(obj.export()).lstrip('\n') @@ -352,26 +356,28 @@ Launch a single page. """ # Build master and header objects, process #forward directives - hidden = oerrors = None + oheader = None while True: - if oerrors is not None and oerrors != self._header.errors: - raise TinCanError("{0}: invalid redirect") - self._template = TemplateFile(self._fspath) + try: + self._template = TemplateFile(self._fspath) + except IOError as e: + raise TinCanError(str(e)) from e try: self._header = TemplateHeader(self._template.header) except TemplateHeaderError as e: raise TinCanError("{0}: {1!s}".format(self._fspath, e)) from e - oerrors = self._header.errors - if hidden is None: - hidden = self._header.hidden - elif self._header.errors is not None: - raise TinCanError("{0}: #forward to #errors not allowed".format(self._origin)) + if oheader is None: + oheader = self._header # save original header + elif (oheader.errors is None) != (self._header.errors is None): + raise TinCanError("{0}: invalid #forward".format(self._origin)) if self._header.forward is None: break + print("forwarding from:", self._urlpath) # debug self._redirect() + print("forwarded to:", self._urlpath) # debug # If this is a #hidden page, we ignore it for now, since hidden pages # don't get routes made for them. - if hidden and not self._headers.errors: + if oheader.hidden and not oheader.errors: return # Get the code-behind #python if self._header.python is not None: @@ -391,8 +397,8 @@ self._body = self._tclass(source=self._template.body) self._body.prepare() # If this is an #errors page, register it as such. - if self._header.errors is not None: - self._mkerror() + if oheader.errors is not None: + self._mkerror(oheader.errors) return # this implies #hidden # Get #methods for this route if self._header.methods is None: @@ -408,9 +414,9 @@ def _splitpath(self, unsplit): return _normpath(self._subdir, unsplit) - def _mkerror(self): + def _mkerror(self, rerrors): try: - errors = [ int(i) for i in self._header.errors.split() ] + errors = [ int(i) for i in rerrors.split() ] except ValueError as e: raise TinCanError("{0}: bad #errors line".format(self._urlpath)) from e if not errors: @@ -467,13 +473,13 @@ try: rlist = self._splitpath(self._header.forward) forw = '/' + '/'.join(rlist) - if forw in self.seen: + if forw in self._seen: raise TinCanError("{0}: #forward loop".format(self._origin)) self._seen.add(forw) rname = rlist.pop() except IndexError as e: raise TinCanError("{0}: invalid #forward".format(self._urlpath)) from e - name, ext = os.path.splitext(rname)[1] + name, ext = os.path.splitext(rname) if ext != _TEXTEN: raise TinCanError("{0}: invalid #forward".format(self._urlpath)) self._subdir = rlist