Mercurial > cgi-bin > hgweb.cgi > tincan
changeset 11:8037bad7d5a8 draft
Update documentation, fix some #forward bugs.
author | David Barts <n5jrn@me.com> |
---|---|
date | Wed, 15 May 2019 00:00:45 -0700 |
parents | 84998cd4e123 |
children | 496d43d551d2 |
files | code_behind.html pspx.html tincan.py |
diffstat | 3 files changed, 48 insertions(+), 24 deletions(-) [+] |
line wrap: on
line diff
--- a/code_behind.html Mon May 13 21:24:48 2019 -0700 +++ b/code_behind.html Wed May 15 00:00:45 2019 -0700 @@ -15,7 +15,7 @@ file names match while only the extensions differ; e.g. <var>foo.py</var> will contain the code-behind logic associated with <var>foo.pspx</var>. Use of the <code>#python</code> and/or <code>#template</code> header - directives will of course change this default association.</p> + directives can of course change this default association.</p> <p>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 <var>Page</var> (normal pages) or <var>ErrorPage</var> (error @@ -42,6 +42,21 @@ method; the default behavior as described in the <em>Default Template Variables</em> section of the template documentation is normally sufficient.</p> + <h3>Page Objects</h3> + <p>These contain the code-behind for normal pages. When the <var>handle</var> + method begins executing, they contain two instance variables: <var>request</var> + (a <var>bottle.Request</var> object) and <var>response</var> (a <var>bottle.Response</var> + object). </p> + <h3>ErrorPage Objects</h3> + <p>These contain the code-behind for error pages. When the <var>handle</var> + method begins executing, they contain two instance variables: <var>request</var> + (a <var>bottle.Request</var> object) and <var>error</var> (a <var>bottle.HTTPError</var> + object). </p> + <h3>The Application Context</h3> + <p>There is no separate standard instance variable in either <var>Page</var> + or <var>ErrorPage</var> that provides such, because it is available via + <var> request.app</var>. See the Bottle documentation for more + information.</p> <h2>Code-Behind is Optional</h2> <p>If you define a template with no code-behind file, TinCan will use either <var>Page</var> or <var>ErrorPage</var> as appropriate, which will
--- 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.</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 <var>#</var>, such as Cheetah.</dd> + <dd>Marks the last line of the headers. Since the end of the header lines + is implicitly marked by the first line that does not start with <var>#</var>, + this is needed only for templating languages where lines often start + with <var>#</var>, such as Cheetah.</dd> <dt><code>#errors</code></dt> <dd>This is an error page which handles the specified HTTP error codes. See the subsection on error pages below. </dd> @@ -74,10 +76,11 @@ class as appropriate. </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. - 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 <code>#end</code> 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.)</p> <p>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
--- 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