Mercurial > cgi-bin > hgweb.cgi > tincan
comparison tincan.py @ 5:31bb8400e6e3 draft
Add #end header, fix #errors.
author | David Barts <n5jrn@me.com> |
---|---|
date | Mon, 13 May 2019 14:47:04 -0700 |
parents | 0d47859f792a |
children | a3823da7bb45 |
comparison
equal
deleted
inserted
replaced
4:0d47859f792a | 5:31bb8400e6e3 |
---|---|
12 import importlib | 12 import importlib |
13 from inspect import isclass | 13 from inspect import isclass |
14 import io | 14 import io |
15 import py_compile | 15 import py_compile |
16 from stat import S_ISDIR, S_ISREG | 16 from stat import S_ISDIR, S_ISREG |
17 from string import whitespace | |
17 | 18 |
18 import bottle | 19 import bottle |
19 | 20 |
20 # E x c e p t i o n s | 21 # E x c e p t i o n s |
21 | 22 |
67 depending on the selected templating engine. The body part has | 68 depending on the selected templating engine. The body part has |
68 each header line replaced by a blank line. This preserves the overall | 69 each header line replaced by a blank line. This preserves the overall |
69 line numbering when processing the body. The added newlines are normally | 70 line numbering when processing the body. The added newlines are normally |
70 stripped out before the rendered page is sent back to the client. | 71 stripped out before the rendered page is sent back to the client. |
71 """ | 72 """ |
73 _END = "#end" | |
74 _LEND = len(_END) | |
75 _WS = set(whitespace) | |
76 | |
72 def __init__(self, raw, encoding='utf-8'): | 77 def __init__(self, raw, encoding='utf-8'): |
73 if isinstance(raw, io.TextIOBase): | 78 if isinstance(raw, io.TextIOBase): |
74 self._do_init(raw) | 79 self._do_init(raw) |
75 elif isinstance(raw, str): | 80 elif isinstance(raw, str): |
76 with open(raw, "r", encoding=encoding) as fp: | 81 with open(raw, "r", encoding=encoding) as fp: |
93 def _header(self, line): | 98 def _header(self, line): |
94 if not line.startswith('#'): | 99 if not line.startswith('#'): |
95 self._state = self._body | 100 self._state = self._body |
96 self._state(line) | 101 self._state(line) |
97 return | 102 return |
103 if line.startswith(self._END) and (len(line) == self._LEND or line[self._LEND] in self._WS): | |
104 self._state = self._body | |
98 self._hbuf.append(line) | 105 self._hbuf.append(line) |
99 self._bbuf.append("\n") | 106 self._bbuf.append("\n") |
100 | 107 |
101 def _body(self, line): | 108 def _body(self, line): |
102 self._bbuf.append(line) | 109 self._bbuf.append(line) |
127 if not line.startswith("#"): | 134 if not line.startswith("#"): |
128 raise TemplateHeaderException("Does not start with '#'.", count) | 135 raise TemplateHeaderException("Does not start with '#'.", count) |
129 try: | 136 try: |
130 rna, rpa = line.split(maxsplit=1) | 137 rna, rpa = line.split(maxsplit=1) |
131 except ValueError: | 138 except ValueError: |
132 raise TemplateHeaderException("Missing parameter.", count) | 139 rna = line.rstrip() |
140 rpa = None | |
133 # Get name, ignoring remarks. | 141 # Get name, ignoring remarks. |
134 name = rna[1:] | 142 name = rna[1:] |
135 if name == "rem": | 143 if name == "rem": |
136 continue | 144 continue |
145 if name == "end": | |
146 break | |
137 if name not in nameset: | 147 if name not in nameset: |
138 raise TemplateHeaderException("Invalid directive: {0!r}".format(rna), count) | 148 raise TemplateHeaderException("Invalid directive: {0!r}".format(rna), count) |
139 if name in seen: | 149 if name in seen: |
140 raise TemplateHeaderException("Duplicate {0!r} directive.".format(rna), count) | 150 raise TemplateHeaderException("Duplicate {0!r} directive.".format(rna), count) |
141 seen.add(name) | 151 seen.add(name) |
142 # Flags | 152 # Flags |
143 if name in self._FLAGS: | 153 if name in self._FNAMES: |
144 setattr(self, name, True) | 154 setattr(self, name, True) |
145 continue | 155 continue |
146 # Get parameter | 156 # Get parameter |
157 if rpa is None: | |
158 raise TemplateHeaderException("Missing parameter.", count) | |
147 param = rpa.strip() | 159 param = rpa.strip() |
148 for i in [ "'", '"']: | 160 for i in [ "'", '"']: |
149 if param.startswith(i) and param.endswith(i): | 161 if param.startswith(i) and param.endswith(i): |
150 param = ast.literal_eval(param) | 162 param = ast.literal_eval(param) |
151 break | 163 break |
292 def __init__(self, template): | 304 def __init__(self, template): |
293 self._template = template | 305 self._template = template |
294 self._template.prepare() | 306 self._template.prepare() |
295 | 307 |
296 def __call__(self, e): | 308 def __call__(self, e): |
297 return self._template.render(e=e, request=bottle.request).lstrip('\n') | 309 return self._template.render(error=e, request=bottle.request).lstrip('\n') |
298 | 310 |
299 class _TinCanRoute(object): | 311 class _TinCanRoute(object): |
300 """ | 312 """ |
301 A route created by the TinCan launcher. | 313 A route created by the TinCan launcher. |
302 """ | 314 """ |
382 errors = range(_ERRMIN, _ERRMAX+1) | 394 errors = range(_ERRMIN, _ERRMAX+1) |
383 route = _TinCanErrorRoute(self._tclass(source=self._template.body)) | 395 route = _TinCanErrorRoute(self._tclass(source=self._template.body)) |
384 for error in errors: | 396 for error in errors: |
385 if error < _ERRMIN or error > _ERRMAX: | 397 if error < _ERRMIN or error > _ERRMAX: |
386 raise TinCanError("{0}: bad #errors code".format(self._urlpath)) | 398 raise TinCanError("{0}: bad #errors code".format(self._urlpath)) |
387 self._app.error(code=error, callback=route) | 399 self._app.error_handler[error] = route # XXX |
388 | 400 |
389 def _getclass(self): | 401 def _getclass(self): |
390 pypath = os.path.normpath(os.path.join(self._fsroot, *self._splitpath(self._python))) | 402 pypath = os.path.normpath(os.path.join(self._fsroot, *self._splitpath(self._python))) |
391 pycpath = pypath + 'c' | 403 pycpath = pypath + 'c' |
392 try: | 404 try: |