annotate tincan.py @ 25:e93e5e746cc5 draft header-includes

Preliminary debugging, still not fully tested.
author David Barts <n5jrn@me.com>
date Sun, 26 May 2019 11:43:48 -0700
parents 34d3cfcd37ef
children cc6ba7834294
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
1 #!/usr/bin/env python3
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
2 # -*- coding: utf-8 -*-
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
3 # As with Bottle, it's all in one big, ugly file. For now.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
4
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
5 # I m p o r t s
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
6
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
7 import os, sys
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
8 import ast
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
9 import binascii
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
10 from base64 import b16encode, b16decode
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
11 import functools
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
12 import importlib
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
13 from inspect import isclass
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
14 import io
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
15 import py_compile
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
16 from stat import S_ISDIR, S_ISREG
5
31bb8400e6e3 Add #end header, fix #errors.
David Barts <n5jrn@me.com>
parents: 4
diff changeset
17 from string import whitespace
17
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
18 import traceback
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
19 import urllib
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
20
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
21 import bottle
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
22
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
23 # E x c e p t i o n s
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
24
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
25 class TinCanException(Exception):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
26 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
27 The parent class of all exceptions we raise.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
28 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
29 pass
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
30
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
31 class TemplateHeaderError(TinCanException):
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
32 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
33 Raised upon encountering a syntax error in the template headers.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
34 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
35 def __init__(self, message, line):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
36 super().__init__(message, line)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
37 self.message = message
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
38 self.line = line
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
39
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
40 def __str__(self):
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
41 return "line {0}: {1}".format(self.line, self.message)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
42
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
43 class IncludeError(TinCanException):
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
44 """
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
45 Raised when we run into problems #include'ing something, usually
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
46 because it doesn't exist.
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
47 """
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
48 def __init__(self, message, source):
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
49 super().__init__(message, source)
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
50 self.message = message
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
51 self.source = source
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
52
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
53 def __str__(self):
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
54 return "{0}: #include error: {1}".format(self.source, self.message)
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
55
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
56 class ForwardException(TinCanException):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
57 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
58 Raised to effect the flow control needed to do a forward (server-side
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
59 redirect). It is ugly to do this, but other Python frameworks do and
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
60 there seems to be no good alternative.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
61 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
62 def __init__(self, target):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
63 self.target = target
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
64
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
65 class TinCanError(TinCanException):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
66 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
67 General-purpose exception thrown by TinCan when things go wrong, often
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
68 when attempting to launch webapps.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
69 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
70 pass
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
71
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
72 # T e m p l a t e s
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
73 #
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
74 # Template (.pspx) files. These are standard templates for a supported
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
75 # template engine, but with an optional set of header lines that begin
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
76 # with '#'.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
77
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
78 class TemplateFile(object):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
79 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
80 Parse a template file into a header part and the body part. The header
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
81 is always a leading set of lines, each starting with '#', that is of the
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
82 same format regardless of the template body. The template body varies
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
83 depending on the selected templating engine. The body part has
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
84 each header line replaced by a blank line. This preserves the overall
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
85 line numbering when processing the body. The added newlines are normally
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
86 stripped out before the rendered page is sent back to the client.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
87 """
5
31bb8400e6e3 Add #end header, fix #errors.
David Barts <n5jrn@me.com>
parents: 4
diff changeset
88 _END = "#end"
31bb8400e6e3 Add #end header, fix #errors.
David Barts <n5jrn@me.com>
parents: 4
diff changeset
89 _LEND = len(_END)
31bb8400e6e3 Add #end header, fix #errors.
David Barts <n5jrn@me.com>
parents: 4
diff changeset
90 _WS = set(whitespace)
31bb8400e6e3 Add #end header, fix #errors.
David Barts <n5jrn@me.com>
parents: 4
diff changeset
91
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
92 def __init__(self, raw, encoding='utf-8'):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
93 if isinstance(raw, io.TextIOBase):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
94 self._do_init(raw)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
95 elif isinstance(raw, str):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
96 with open(raw, "r", encoding=encoding) as fp:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
97 self._do_init(fp)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
98 else:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
99 raise TypeError("Expecting a string or Text I/O object.")
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
100
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
101 def _do_init(self, fp):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
102 self._hbuf = []
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
103 self._bbuf = []
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
104 self._state = self._header
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
105 while True:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
106 line = fp.readline()
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
107 if line == '':
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
108 break
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
109 self._state(line)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
110 self.header = ''.join(self._hbuf)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
111 self.body = ''.join(self._bbuf)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
112
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
113 def _header(self, line):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
114 if not line.startswith('#'):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
115 self._state = self._body
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
116 self._state(line)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
117 return
5
31bb8400e6e3 Add #end header, fix #errors.
David Barts <n5jrn@me.com>
parents: 4
diff changeset
118 if line.startswith(self._END) and (len(line) == self._LEND or line[self._LEND] in self._WS):
31bb8400e6e3 Add #end header, fix #errors.
David Barts <n5jrn@me.com>
parents: 4
diff changeset
119 self._state = self._body
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
120 self._hbuf.append(line)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
121
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
122 def _body(self, line):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
123 self._bbuf.append(line)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
124
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
125 class TemplateHeader(object):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
126 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
127 Parses and represents a set of header lines.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
128 """
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
129 _NAMES = [ "errors", "forward", "methods", "python", "template" ]
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
130 _FNAMES = [ "hidden" ]
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
131 _ANAMES = [ "include" ]
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
132
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
133 def __init__(self, string):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
134 # Initialize our state
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
135 for i in self._NAMES:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
136 setattr(self, i, None)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
137 for i in self._FNAMES:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
138 setattr(self, i, False)
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
139 for i in self._ANAMES:
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
140 setattr(self, i, [])
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
141 # Parse the string
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
142 count = 0
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
143 nameset = set(self._NAMES + self._FNAMES + self._ANAMES)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
144 seen = set()
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
145 lines = string.split("\n")
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
146 if lines and lines[-1] == "":
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
147 del lines[-1]
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
148 for line in lines:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
149 # Get line
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
150 count += 1
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
151 if not line.startswith("#"):
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
152 raise TemplateHeaderError("Does not start with '#'.", count)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
153 try:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
154 rna, rpa = line.split(maxsplit=1)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
155 except ValueError:
5
31bb8400e6e3 Add #end header, fix #errors.
David Barts <n5jrn@me.com>
parents: 4
diff changeset
156 rna = line.rstrip()
31bb8400e6e3 Add #end header, fix #errors.
David Barts <n5jrn@me.com>
parents: 4
diff changeset
157 rpa = None
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
158 # Get name, ignoring remarks.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
159 name = rna[1:]
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
160 if name == "rem":
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
161 continue
5
31bb8400e6e3 Add #end header, fix #errors.
David Barts <n5jrn@me.com>
parents: 4
diff changeset
162 if name == "end":
31bb8400e6e3 Add #end header, fix #errors.
David Barts <n5jrn@me.com>
parents: 4
diff changeset
163 break
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
164 if name not in nameset:
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
165 raise TemplateHeaderError("Invalid directive: {0!r}".format(rna), count)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
166 if name in seen:
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
167 raise TemplateHeaderError("Duplicate {0!r} directive.".format(rna), count)
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
168 if name not in self._ANAMES:
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
169 seen.add(name)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
170 # Flags
5
31bb8400e6e3 Add #end header, fix #errors.
David Barts <n5jrn@me.com>
parents: 4
diff changeset
171 if name in self._FNAMES:
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
172 setattr(self, name, True)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
173 continue
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
174 # Get parameter
5
31bb8400e6e3 Add #end header, fix #errors.
David Barts <n5jrn@me.com>
parents: 4
diff changeset
175 if rpa is None:
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
176 raise TemplateHeaderError("Missing parameter.", count)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
177 param = rpa.strip()
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
178 for i in [ "'", '"']:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
179 if param.startswith(i) and param.endswith(i):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
180 param = ast.literal_eval(param)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
181 break
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
182 # Update this object
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
183 if name in self._ANAMES:
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
184 getattr(self, name).append(param)
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
185 else:
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
186 setattr(self, name, param)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
187
23
e8b6ee7e5b6b Well, *that* attempt at includes didn't work. Revert.
David Barts <n5jrn@me.com>
parents: 22
diff changeset
188 # C h a m e l e o n
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
189 #
23
e8b6ee7e5b6b Well, *that* attempt at includes didn't work. Revert.
David Barts <n5jrn@me.com>
parents: 22
diff changeset
190 # Support for Chameleon templates (the kind TinCan uses by default).
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
191
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
192 class ChameleonTemplate(bottle.BaseTemplate):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
193 def prepare(self, **options):
23
e8b6ee7e5b6b Well, *that* attempt at includes didn't work. Revert.
David Barts <n5jrn@me.com>
parents: 22
diff changeset
194 from chameleon import PageTemplate, PageTemplateFile
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
195 if self.source:
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
196 self.tpl = PageTemplate(self.source, encoding=self.encoding,
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
197 **options)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
198 else:
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
199 self.tpl = PageTemplateFile(self.filename, encoding=self.encoding,
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
200 search_path=self.lookup, **options)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
201
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
202 def render(self, *args, **kwargs):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
203 for dictarg in args:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
204 kwargs.update(dictarg)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
205 _defaults = self.defaults.copy()
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
206 _defaults.update(kwargs)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
207 return self.tpl.render(**_defaults)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
208
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
209 chameleon_template = functools.partial(bottle.template, template_adapter=ChameleonTemplate)
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
210 chameleon_view = functools.partial(bottle.view, template_adapter=ChameleonTemplate)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
211
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
212 # U t i l i t i e s
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
213
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
214 def _normpath(base, unsplit):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
215 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
216 Split, normalize and ensure a possibly relative path is absolute. First
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
217 argument is a list of directory names, defining a base. Second
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
218 argument is a string, which may either be relative to that base, or
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
219 absolute. Only '/' is supported as a separator.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
220 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
221 scratch = unsplit.strip('/').split('/')
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
222 if not unsplit.startswith('/'):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
223 scratch = base + scratch
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
224 ret = []
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
225 for i in scratch:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
226 if i == '.':
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
227 continue
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
228 if i == '..':
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
229 ret.pop() # may raise IndexError
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
230 continue
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
231 ret.append(i)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
232 return ret
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
233
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
234 def _mangle(string):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
235 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
236 Turn a possibly troublesome identifier into a mangled one.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
237 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
238 first = True
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
239 ret = []
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
240 for ch in string:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
241 if ch == '_' or not (ch if first else "x" + ch).isidentifier():
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
242 ret.append('_')
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
243 ret.append(b16encode(ch.encode("utf-8")).decode("us-ascii"))
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
244 else:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
245 ret.append(ch)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
246 first = False
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
247 return ''.join(ret)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
248
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
249 # The TinCan class. Simply a Bottle webapp that contains a forward method, so
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
250 # the code-behind can call request.app.forward().
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
251
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
252 class TinCan(bottle.Bottle):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
253 def forward(self, target):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
254 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
255 Forward this request to the specified target route.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
256 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
257 source = bottle.request.environ['PATH_INFO']
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
258 base = source.strip('/').split('/')[:-1]
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
259 if bottle.request.environ.get(_FTYPE, False):
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
260 raise TinCanError("{0}: forward from error page".format(source))
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
261 try:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
262 exc = ForwardException('/' + '/'.join(_normpath(base, target)))
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
263 except IndexError as e:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
264 raise TinCanError("{0}: invalid forward to {1!r}".format(source, target)) from e
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
265 raise exc
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
266
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
267 # C o d e B e h i n d
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
268 #
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
269 # Represents the code-behind of one of our pages. This gets subclassed, of
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
270 # course.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
271
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
272 class BasePage(object):
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
273 """
11
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
274 The parent class of both error and normal pages' code-behind.
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
275 """
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
276 def handle(self):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
277 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
278 This is the entry point for the code-behind logic. It is intended
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
279 to be overridden.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
280 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
281 pass
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
282
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
283 def export(self):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
284 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
285 Export template variables. The default behavior is to export all
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
286 non-hidden non-callables that don't start with an underscore.
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
287 This method can be overridden if a different behavior is
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
288 desired. It should always return a dict or dict-like object.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
289 """
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
290 ret = { 'page': self }
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
291 for name in dir(self):
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
292 if name in self._HIDDEN or name.startswith('_'):
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
293 continue
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
294 value = getattr(self, name)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
295 if callable(value):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
296 continue
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
297 ret[name] = value
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
298 return ret
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
299
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
300 class Page(BasePage):
11
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
301 """
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
302 The code-behind for a normal page.
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
303 """
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
304 # Non-private things we refuse to export anyhow.
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
305 _HIDDEN = set([ "request", "response" ])
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
306
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
307 def __init__(self, req, resp):
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
308 """
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
309 Constructor. This is a lightweight operation.
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
310 """
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
311 self.request = req # app context is request.app in Bottle
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
312 self.response = resp
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
313
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
314 class ErrorPage(BasePage):
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
315 """
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
316 The code-behind for an error page.
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
317 """
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
318 _HIDDEN = set()
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
319
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
320 def __init__(self, req, err):
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
321 """
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
322 Constructor. This is a lightweight operation.
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
323 """
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
324 self.request = req
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
325 self.error = err
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
326
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
327 # I n c l u s i o n
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
328 #
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
329 # This is where the #include directives get processed
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
330
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
331 _IEXTEN = ".pt"
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
332
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
333 class _Includer(object):
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
334 def __init__(self, base, subdir, name, included=None, encoding="utf-8"):
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
335 self.base = base
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
336 self.subdir = subdir
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
337 self.name = name
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
338 self.included = set() if included is None else included
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
339 self.encoding = encoding
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
340 self._buf = []
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
341
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
342 def render(self, includes, body):
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
343 for i in includes:
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
344 if i.startswith('<') and i.endswith('>'):
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
345 self._buf.append(self._render1([_WINF, "tlib"], i[1:-1]))
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
346 else:
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
347 self._buf.append(self._render1(self.subdir, i))
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
348 self._buf.append(body)
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
349 return ''.join(self._buf)
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
350
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
351 def _render1(self, subdir, path):
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
352 # Reject bad file names
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
353 if not path.endswith(_IEXTEN) or path.endswith(_TEXTEN):
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
354 raise IncludeError("file names must end with {0} or {1}".format(_IEXTEN, _TEXTEN), self.name)
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
355 # Normalize
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
356 rawpath = _normpath(subdir, path)
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
357 # Only include once
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
358 relpath = '/' + '/'.join(rawpath)
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
359 if relpath in self.included:
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
360 return
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
361 self.included.add(relpath)
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
362 # Do actual inclusion of a file
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
363 npath = os.path.join(self.base, *rawpath)
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
364 nsubdir = rawpath[:-1]
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
365 try:
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
366 tf = TemplateFile(npath)
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
367 except OSError as e:
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
368 raise IncludeError(str(e), self.name) from e
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
369 try:
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
370 th = TemplateHeader(tf.header)
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
371 except TemplateHeaderError as e:
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
372 raise IncludeError(str(e), npath) from e
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
373 # Reject unsupported crap (included files can only #include)
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
374 for i in dir(th):
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
375 if i.startswith('_') or i == 'include':
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
376 continue
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
377 v = getattr(th, i)
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
378 if callable(v):
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
379 continue
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
380 if v is not None and v != False:
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
381 raise IncludeError(npath, "unsupported #{0}".format(i))
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
382 # Inclusion is recursive...
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
383 nested = _Includer(self.base, nsubdir, relpath,
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
384 included=self.included, encoding=self.encoding)
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
385 return nested.render(th.include, tf.body)
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
386
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
387 # R o u t e s
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
388 #
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
389 # Represents a route in TinCan. Our launcher creates these on-the-fly based
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
390 # on the files it finds.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
391
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
392 _ERRMIN = 400
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
393 _ERRMAX = 599
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
394 _PEXTEN = ".py"
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
395 _TEXTEN = ".pspx"
1
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
396 _FLOOP = "tincan.forwards"
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
397 _FORIG = "tincan.origin"
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
398 _FTYPE = "tincan.iserror"
1
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
399
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
400 class _TinCanErrorRoute(object):
1
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
401 """
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
402 A route to an error page. These don't get routes created for them,
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
403 and are only reached if an error routes them there. Unless you create
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
404 custom code-behind, only two variables are available to your template:
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
405 request (bottle.Request) and error (bottle.HTTPError).
1
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
406 """
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
407 def __init__(self, template, klass):
1
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
408 self._template = template
23
e8b6ee7e5b6b Well, *that* attempt at includes didn't work. Revert.
David Barts <n5jrn@me.com>
parents: 22
diff changeset
409 self._template.prepare()
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
410 self._class = klass
1
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
411
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
412 def __call__(self, e):
11
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
413 bottle.request.environ[_FTYPE] = True
17
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
414 try:
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
415 obj = self._class(bottle.request, e)
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
416 obj.handle()
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
417 return self._template.render(obj.export())
17
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
418 except bottle.HTTPResponse as e:
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
419 return e
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
420 except Exception as e:
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
421 traceback.print_exc()
18
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
422 # Bottle doesn't allow error handlers to themselves cause
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
423 # errors, most likely as a measure to prevent looping. So
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
424 # this will cause a "Critical error while processing request"
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
425 # page to be displayed, and any installed error pages to be
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
426 # ignored.
17
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
427 raise bottle.HTTPError(status=500, exception=e)
1
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
428
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
429 class _TinCanRoute(object):
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
430 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
431 A route created by the TinCan launcher.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
432 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
433 def __init__(self, launcher, name, subdir):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
434 self._fsroot = launcher.fsroot
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
435 self._urlroot = launcher.urlroot
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
436 self._name = name
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
437 self._python = name + _PEXTEN
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
438 self._fspath = os.path.join(launcher.fsroot, *subdir, name + _TEXTEN)
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
439 self._urlpath = self._urljoin(launcher.urlroot, *subdir, name + _TEXTEN)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
440 self._origin = self._urlpath
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
441 self._subdir = subdir
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
442 self._seen = set()
23
e8b6ee7e5b6b Well, *that* attempt at includes didn't work. Revert.
David Barts <n5jrn@me.com>
parents: 22
diff changeset
443 self._tclass = launcher.tclass
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
444 self._app = launcher.app
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
445 self._save_includes = launcher.debug
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
446
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
447 def launch(self):
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
448 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
449 Launch a single page.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
450 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
451 # Build master and header objects, process #forward directives
11
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
452 oheader = None
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
453 while True:
11
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
454 try:
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
455 self._template = TemplateFile(self._fspath)
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
456 except IOError as e:
12
496d43d551d2 More redirecting fixes and improved error reportage.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
457 if oheader is not None:
496d43d551d2 More redirecting fixes and improved error reportage.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
458 note = "{0}: invalid #forward: ".format(self._origin)
496d43d551d2 More redirecting fixes and improved error reportage.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
459 else:
496d43d551d2 More redirecting fixes and improved error reportage.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
460 note = ""
496d43d551d2 More redirecting fixes and improved error reportage.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
461 raise TinCanError("{0}{1!s}".format(note, e)) from e
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
462 try:
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
463 self._header = TemplateHeader(self._template.header)
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
464 except TemplateHeaderError as e:
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
465 raise TinCanError("{0}: {1!s}".format(self._fspath, e)) from e
11
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
466 if oheader is None:
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
467 oheader = self._header # save original header
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
468 elif (oheader.errors is None) != (self._header.errors is None):
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
469 raise TinCanError("{0}: invalid #forward".format(self._origin))
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
470 if self._header.forward is None:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
471 break
12
496d43d551d2 More redirecting fixes and improved error reportage.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
472 # print("forwarding from:", self._urlpath) # debug
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
473 self._redirect()
12
496d43d551d2 More redirecting fixes and improved error reportage.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
474 # print("forwarded to:", self._urlpath) # debug
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
475 # If this is a #hidden page, we ignore it for now, since hidden pages
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
476 # don't get routes made for them.
11
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
477 if oheader.hidden and not oheader.errors:
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
478 return
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
479 # Get the code-behind #python
15
560c8fb55e4a Fix bugs in #python directive, make code-behind class loading simpler.
David Barts <n5jrn@me.com>
parents: 14
diff changeset
480 if self._header.python is None:
560c8fb55e4a Fix bugs in #python directive, make code-behind class loading simpler.
David Barts <n5jrn@me.com>
parents: 14
diff changeset
481 self._python_specified = False
560c8fb55e4a Fix bugs in #python directive, make code-behind class loading simpler.
David Barts <n5jrn@me.com>
parents: 14
diff changeset
482 else:
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
483 if not self._header.python.endswith(_PEXTEN):
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
484 raise TinCanError("{0}: #python files must end in {1}".format(self._urlpath, _PEXTEN))
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
485 self._python = self._header.python
15
560c8fb55e4a Fix bugs in #python directive, make code-behind class loading simpler.
David Barts <n5jrn@me.com>
parents: 14
diff changeset
486 self._python_specified = True
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
487 # Obtain a class object by importing and introspecting a module.
3
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
488 self._getclass()
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
489 # Build body object (#template) and process #includes.
3
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
490 if self._header.template is not None:
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
491 if not self._header.template.endswith(_TEXTEN):
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
492 raise TinCanError("{0}: #template files must end in {1}".format(self._urlpath, _TEXTEN))
16
448fc3d534f8 Improve error reportage.
David Barts <n5jrn@me.com>
parents: 15
diff changeset
493 try:
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
494 rawpath = self._splitpath(self._header.template)
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
495 tsubdir = rawpath[:-1]
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
496 tname = rawpath[-1]
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
497 tpath = os.path.normpath(os.path.join(self._fsroot, *rawpath))
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
498 turlpath = '/' + self._urljoin(rawpath)
16
448fc3d534f8 Improve error reportage.
David Barts <n5jrn@me.com>
parents: 15
diff changeset
499 tfile = TemplateFile(tpath)
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
500 thead = TemplateHeader(tfile.header)
24
34d3cfcd37ef First batch of work on getting a #include header. Unfinished.
David Barts <n5jrn@me.com>
parents: 23
diff changeset
501 except (OSError, TemplateHeaderError) as e:
16
448fc3d534f8 Improve error reportage.
David Barts <n5jrn@me.com>
parents: 15
diff changeset
502 raise TinCanError("{0}: invalid #template: {1!s}".format(self._urlpath, e)) from e
448fc3d534f8 Improve error reportage.
David Barts <n5jrn@me.com>
parents: 15
diff changeset
503 except IndexError as e:
448fc3d534f8 Improve error reportage.
David Barts <n5jrn@me.com>
parents: 15
diff changeset
504 raise TinCanError("{0}: invalid #template".format(self._urlpath)) from e
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
505 r = self._getbody(tsubdir, tname, thead.include, tfile.body)
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
506 self._dumpbody(r, tpath, turlpath)
3
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
507 else:
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
508 r = self._getbody(self._subdir, self._name+_TEXTEN,
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
509 self._header.include, self._template.body)
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
510 self._dumpbody(r, self._fspath, self._urlpath)
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
511 # If this is an #errors page, register it as such.
11
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
512 if oheader.errors is not None:
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
513 self._mkerror(oheader.errors)
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
514 return # this implies #hidden
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
515 # Get #methods for this route
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
516 if self._header.methods is None:
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
517 methods = [ 'GET' ]
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
518 else:
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
519 methods = [ i.upper() for i in self._header.methods.split() ]
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
520 if not methods:
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
521 raise TinCanError("{0}: no #methods specified".format(self._urlpath))
3
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
522 # Register this thing with Bottle
6
a3823da7bb45 Minor tweaks.
David Barts <n5jrn@me.com>
parents: 5
diff changeset
523 print("adding route:", self._origin, '('+','.join(methods)+')') # debug
3
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
524 self._app.route(self._origin, methods, self)
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
525
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
526 def _getbody(self, subdir, name, include, body):
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
527 includer = _Includer(self._fsroot, subdir, name)
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
528 try:
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
529 rendered = includer.render(include, body)
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
530 except IncludeError as e:
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
531 raise TinCanError(str(e)) from e
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
532 try:
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
533 self._body = self._tclass(source=rendered)
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
534 self._body.prepare()
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
535 except Exception as e:
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
536 raise TinCanError("{0}: template error: {1!s}".format(urlpath, e)) from e
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
537 return rendered
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
538
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
539 def _dumpbody(self, rendered, based_on, logname):
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
540 if self._save_includes:
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
541 try:
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
542 with open(based_on + 'i', w) as fp:
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
543 fp.write(rendered)
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
544 except OSError as e:
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
545 raise TinCanError("{0}: {1!s}".format(logname, e)) from e
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
546
3
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
547 def _splitpath(self, unsplit):
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
548 return _normpath(self._subdir, unsplit)
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
549
11
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
550 def _mkerror(self, rerrors):
3
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
551 try:
11
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
552 errors = [ int(i) for i in rerrors.split() ]
3
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
553 except ValueError as e:
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
554 raise TinCanError("{0}: bad #errors line".format(self._urlpath)) from e
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
555 if not errors:
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
556 errors = range(_ERRMIN, _ERRMAX+1)
23
e8b6ee7e5b6b Well, *that* attempt at includes didn't work. Revert.
David Barts <n5jrn@me.com>
parents: 22
diff changeset
557 route = _TinCanErrorRoute(self._tclass(source=self._template.body), self._class)
3
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
558 for error in errors:
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
559 if error < _ERRMIN or error > _ERRMAX:
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
560 raise TinCanError("{0}: bad #errors code".format(self._urlpath))
5
31bb8400e6e3 Add #end header, fix #errors.
David Barts <n5jrn@me.com>
parents: 4
diff changeset
561 self._app.error_handler[error] = route # XXX
3
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
562
7
57ec65f527e9 Eliminate a stat() call, allow no code-behind on pages.
David Barts <n5jrn@me.com>
parents: 6
diff changeset
563 def _gettime(self, path):
57ec65f527e9 Eliminate a stat() call, allow no code-behind on pages.
David Barts <n5jrn@me.com>
parents: 6
diff changeset
564 try:
57ec65f527e9 Eliminate a stat() call, allow no code-behind on pages.
David Barts <n5jrn@me.com>
parents: 6
diff changeset
565 return os.stat(path).st_mtime
57ec65f527e9 Eliminate a stat() call, allow no code-behind on pages.
David Barts <n5jrn@me.com>
parents: 6
diff changeset
566 except FileNotFoundError:
57ec65f527e9 Eliminate a stat() call, allow no code-behind on pages.
David Barts <n5jrn@me.com>
parents: 6
diff changeset
567 return 0
8
9aaa91247b14 Fix minor buglet.
David Barts <n5jrn@me.com>
parents: 7
diff changeset
568 except OSError as e:
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
569 raise TinCanError(str(e)) from e
7
57ec65f527e9 Eliminate a stat() call, allow no code-behind on pages.
David Barts <n5jrn@me.com>
parents: 6
diff changeset
570
3
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
571 def _getclass(self):
15
560c8fb55e4a Fix bugs in #python directive, make code-behind class loading simpler.
David Barts <n5jrn@me.com>
parents: 14
diff changeset
572 try:
560c8fb55e4a Fix bugs in #python directive, make code-behind class loading simpler.
David Barts <n5jrn@me.com>
parents: 14
diff changeset
573 pypath = os.path.normpath(os.path.join(self._fsroot, *self._splitpath(self._python)))
560c8fb55e4a Fix bugs in #python directive, make code-behind class loading simpler.
David Barts <n5jrn@me.com>
parents: 14
diff changeset
574 except IndexError as e:
560c8fb55e4a Fix bugs in #python directive, make code-behind class loading simpler.
David Barts <n5jrn@me.com>
parents: 14
diff changeset
575 raise TinCanError("{0}: invalid #python".format(self._urlpath)) from e
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
576 klass = ErrorPage if self._header.errors else Page
7
57ec65f527e9 Eliminate a stat() call, allow no code-behind on pages.
David Barts <n5jrn@me.com>
parents: 6
diff changeset
577 # Give 'em a default code-behind if they don't furnish one
57ec65f527e9 Eliminate a stat() call, allow no code-behind on pages.
David Barts <n5jrn@me.com>
parents: 6
diff changeset
578 pytime = self._gettime(pypath)
57ec65f527e9 Eliminate a stat() call, allow no code-behind on pages.
David Barts <n5jrn@me.com>
parents: 6
diff changeset
579 if not pytime:
15
560c8fb55e4a Fix bugs in #python directive, make code-behind class loading simpler.
David Barts <n5jrn@me.com>
parents: 14
diff changeset
580 if self._python_specified:
560c8fb55e4a Fix bugs in #python directive, make code-behind class loading simpler.
David Barts <n5jrn@me.com>
parents: 14
diff changeset
581 raise TinCanError("{0}: #python file not found".format(self._urlpath))
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
582 self._class = klass
7
57ec65f527e9 Eliminate a stat() call, allow no code-behind on pages.
David Barts <n5jrn@me.com>
parents: 6
diff changeset
583 return
57ec65f527e9 Eliminate a stat() call, allow no code-behind on pages.
David Barts <n5jrn@me.com>
parents: 6
diff changeset
584 # Else load the code-behind from a .py file
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
585 pycpath = pypath + 'c'
7
57ec65f527e9 Eliminate a stat() call, allow no code-behind on pages.
David Barts <n5jrn@me.com>
parents: 6
diff changeset
586 pyctime = self._gettime(pycpath)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
587 try:
7
57ec65f527e9 Eliminate a stat() call, allow no code-behind on pages.
David Barts <n5jrn@me.com>
parents: 6
diff changeset
588 if pyctime < pytime:
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
589 py_compile.compile(pypath, cfile=pycpath, doraise=True)
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
590 except py_compile.PyCompileError as e:
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
591 raise TinCanError(str(e)) from e
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
592 except Exception as e:
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
593 raise TinCanError("{0}: {1!s}".format(pypath, e)) from e
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
594 try:
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
595 spec = importlib.util.spec_from_file_location(_mangle(self._name), pycpath)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
596 mod = importlib.util.module_from_spec(spec)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
597 spec.loader.exec_module(mod)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
598 except Exception as e:
16
448fc3d534f8 Improve error reportage.
David Barts <n5jrn@me.com>
parents: 15
diff changeset
599 raise TinCanError("{0}: error importing: {1!s}".format(pycpath, e)) from e
19
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
600 # Locate a suitable class. We look for the "deepest" class object
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
601 # we can find in the inheritance tree.
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
602 self._class = None
19
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
603 score = -1
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
604 ambig = False
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
605 for i in dir(mod):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
606 v = getattr(mod, i)
19
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
607 if not isclass(v):
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
608 continue
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
609 d = self._cldepth(klass, v)
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
610 if d > score:
15
560c8fb55e4a Fix bugs in #python directive, make code-behind class loading simpler.
David Barts <n5jrn@me.com>
parents: 14
diff changeset
611 self._class = v
19
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
612 score = d
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
613 ambig = False
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
614 elif d == score:
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
615 ambig = True
3
c6902cded64d Corrections and reorg.
David Barts <n5jrn@me.com>
parents: 2
diff changeset
616 if self._class is None:
9
75e375b1976a Error pages now can have code-behind.
David Barts <n5jrn@me.com>
parents: 8
diff changeset
617 raise TinCanError("{0}: contains no {1} classes".format(pypath, klass.__name__))
19
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
618 if ambig:
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
619 raise TinCanError("{0}: contains ambiguous {1} classes".format(pypath, klass.__name__))
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
620
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
621 # This might fail for complex inheritance schemes from the classes of
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
622 # interest (so don't use them!).
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
623 def _cldepth(self, base, klass, count=0):
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
624 if klass is object:
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
625 # not found
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
626 return -1
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
627 elif klass is base:
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
628 # just found
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
629 return count
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
630 else:
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
631 # must recurse
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
632 for c in klass.__bases__:
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
633 result = self._cldepth(base, c, count=count+1)
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
634 if result > 0:
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
635 return result
5d9a1b82251a Return the "deepest" subclass; this allows subclassing tincan.Page and
David Barts <n5jrn@me.com>
parents: 18
diff changeset
636 return -1
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
637
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
638 def _redirect(self):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
639 try:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
640 rlist = self._splitpath(self._header.forward)
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
641 forw = '/' + '/'.join(rlist)
11
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
642 if forw in self._seen:
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
643 raise TinCanError("{0}: #forward loop".format(self._origin))
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
644 self._seen.add(forw)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
645 rname = rlist.pop()
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
646 except IndexError as e:
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
647 raise TinCanError("{0}: invalid #forward".format(self._urlpath)) from e
11
8037bad7d5a8 Update documentation, fix some #forward bugs.
David Barts <n5jrn@me.com>
parents: 9
diff changeset
648 name, ext = os.path.splitext(rname)
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
649 if ext != _TEXTEN:
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
650 raise TinCanError("{0}: invalid #forward".format(self._urlpath))
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
651 self._subdir = rlist
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
652 self._python = name + _PEXTEN
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
653 self._fspath = os.path.join(self._fsroot, *self._subdir, rname)
12
496d43d551d2 More redirecting fixes and improved error reportage.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
654 self._urlpath = '/' + self._urljoin(*self._subdir, rname)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
655
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
656 def _urljoin(self, *args):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
657 args = list(args)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
658 if args[0] == '/':
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
659 args[0] = ''
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
660 return '/'.join(args)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
661
1
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
662 def __call__(self):
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
663 """
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
664 This gets called by the framework AFTER the page is launched.
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
665 """
1
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
666 target = None
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
667 try:
17
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
668 obj = self._class(bottle.request, bottle.response)
1
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
669 obj.handle()
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
670 return self._body.render(obj.export())
1
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
671 except ForwardException as fwd:
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
672 target = fwd.target
17
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
673 except bottle.HTTPResponse as e:
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
674 return e
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
675 except Exception as e:
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
676 traceback.print_exc()
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
677 raise bottle.HTTPError(status=500, exception=e)
1
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
678 if target is None:
17
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
679 message = "{0}: unexpected null target".format(self._urlpath)
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
680 sys.stderr.write(message + '\n')
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
681 raise bottle.HTTPError(status=500, exception=TinCanError(message))
1
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
682 # We get here if we are doing a server-side programmatic
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
683 # forward.
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
684 environ = bottle.request.environ
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
685 if _FORIG not in environ:
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
686 environ[_FORIG] = self._urlpath
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
687 if _FLOOP not in environ:
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
688 environ[_FLOOP] = set([self._urlpath])
1
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
689 elif target in environ[_FLOOP]:
17
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
690 message = "{0}: forward loop detected".format(environ[_FORIG])
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
691 sys.stderr.write(message + '\n')
8186de188daf Improve the run-time error handling in code-behinds.
David Barts <n5jrn@me.com>
parents: 16
diff changeset
692 raise bottle.HTTPError(status=500, exception=TinCanError(message))
1
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
693 environ[_FLOOP].add(target)
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
694 environ['bottle.raw_path'] = target
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
695 environ['PATH_INFO'] = urllib.parse.quote(target)
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
696 route, args = self._app.router.match(environ)
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
697 environ['route.handle'] = environ['bottle.route'] = route
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
698 environ['route.url_args'] = args
94b36e721500 Another check in to back stuff up.
David Barts <n5jrn@me.com>
parents: 0
diff changeset
699 return route.call(**args)
0
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
700
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
701 def _mkdict(self, obj):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
702 ret = {}
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
703 for name in dir(obj):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
704 if name.startswith('_'):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
705 continue
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
706 value = getattr(obj, name)
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
707 if not callable(value):
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
708 ret[name] = value
e726fafcffac For backup purposes, UNFINISHED!!
David Barts <n5jrn@me.com>
parents:
diff changeset
709 return ret
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
710
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
711 # L a u n c h e r
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
712
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
713 _WINF = "WEB-INF"
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
714 _BANNED = set([_WINF])
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
715
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
716 class _Launcher(object):
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
717 """
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
718 Helper class for launching webapps.
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
719 """
23
e8b6ee7e5b6b Well, *that* attempt at includes didn't work. Revert.
David Barts <n5jrn@me.com>
parents: 22
diff changeset
720 def __init__(self, fsroot, urlroot, tclass, logger):
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
721 """
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
722 Lightweight constructor. The real action happens in .launch() below.
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
723 """
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
724 self.fsroot = fsroot
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
725 self.urlroot = urlroot
23
e8b6ee7e5b6b Well, *that* attempt at includes didn't work. Revert.
David Barts <n5jrn@me.com>
parents: 22
diff changeset
726 self.tclass = tclass
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
727 self.logger = logger
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
728 self.app = None
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
729 self.errors = 0
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
730 self.debug = False
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
731
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
732 def launch(self):
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
733 """
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
734 Does the actual work of launching something. XXX - modifies sys.path
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
735 and never un-modifies it.
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
736 """
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
737 # Sanity checks
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
738 if not self.urlroot.startswith("/"):
18
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
739 self.errors = 1
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
740 self.logger("urlroot not absolute: {0!r}".format(self.urlroot))
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
741 return self
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
742 if not os.path.isdir(self.fsroot):
18
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
743 self.errors = 1
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
744 self.logger("no such directory: {0!r}".format(self.fsroot))
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
745 return self
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
746 # Make any needed directories. Refuse to launch things that don't
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
747 # contain WEB-INF, to prevent accidental launches of undesired
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
748 # directory trees containing sensitive files.
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
749 winf = os.path.join(self.fsroot, _WINF)
18
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
750 if not os.path.isdir(winf):
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
751 self.errors = 1
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
752 self.logger("no WEB-INF directory in {0!r}".format(self.fsroot))
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
753 return self
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
754 lib = os.path.join(winf, "lib")
18
e88ab99914cf More improvements to the error reportage.
David Barts <n5jrn@me.com>
parents: 17
diff changeset
755 for i in [ lib ]:
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
756 if not os.path.isdir(i):
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
757 os.mkdir(i)
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
758 # Add our private lib directory to sys.path
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
759 sys.path.insert(1, os.path.abspath(lib))
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
760 # Do what we gotta do
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
761 self.app = TinCan()
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
762 self._launch([])
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
763 return self
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
764
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
765 def _launch(self, subdir):
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
766 for entry in os.listdir(os.path.join(self.fsroot, *subdir)):
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
767 if not subdir and entry in _BANNED:
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
768 continue
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
769 etype = os.stat(os.path.join(self.fsroot, *subdir, entry)).st_mode
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
770 if S_ISREG(etype):
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
771 ename, eext = os.path.splitext(entry)
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
772 if eext != _TEXTEN:
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
773 continue # only look at interesting files
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
774 route = _TinCanRoute(self, ename, subdir)
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
775 try:
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
776 route.launch()
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
777 except TinCanError as e:
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
778 self.logger(str(e))
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
779 if self.debug:
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
780 while e.__cause__ != None:
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
781 e = e.__cause__
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
782 self.logger("\t{0}: {1!s}".format(e.__class__.__name__, e))
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
783 self.errors += 1
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
784 elif S_ISDIR(etype):
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
785 self._launch(subdir + [entry])
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
786
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
787 def _logger(message):
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
788 sys.stderr.write(message)
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
789 sys.stderr.write('\n')
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
790
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
791 def launch(fsroot=None, urlroot='/', tclass=ChameleonTemplate, logger=_logger, debug=False):
2
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
792 """
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
793 Launch and return a TinCan webapp. Does not run the app; it is the
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
794 caller's responsibility to call app.run()
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
795 """
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
796 if fsroot is None:
ca6f8ca38cf2 Another backup commit.
David Barts <n5jrn@me.com>
parents: 1
diff changeset
797 fsroot = os.getcwd()
23
e8b6ee7e5b6b Well, *that* attempt at includes didn't work. Revert.
David Barts <n5jrn@me.com>
parents: 22
diff changeset
798 launcher = _Launcher(fsroot, urlroot, tclass, logger)
25
e93e5e746cc5 Preliminary debugging, still not fully tested.
David Barts <n5jrn@me.com>
parents: 24
diff changeset
799 launcher.debug = debug
4
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
800 launcher.launch()
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
801 return launcher.app, launcher.errors
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
802
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
803 # XXX - We cannot implement a command-line launcher here; see the
0d47859f792a Finally got "hello, world" working. Still likely many bugs.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
804 # launcher script for why.