Merge lp:~scott-armitage/pyng/uri-pattern into lp:pyng
- uri-pattern
- Merge into trunk
Proposed by
Scott Armitage
Status: | Merged |
---|---|
Approved by: | Scott Armitage |
Approved revision: | 17 |
Merged at revision: | not available |
Proposed branch: | lp:~scott-armitage/pyng/uri-pattern |
Merge into: | lp:pyng |
Diff against target: | None lines |
To merge this branch: | bzr merge lp:~scott-armitage/pyng/uri-pattern |
Related bugs: | |
Related blueprints: |
Exceptions
(Undefined)
Simple page templating engine
(Undefined)
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Scott Armitage | Approve | ||
Review via email: mp+6787@code.launchpad.net |
Commit message
Added URI handling and basic exception definitions.
Description of the change
To post a comment you must log in.
Revision history for this message
Scott Armitage (scott-armitage) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'PyngPyng/__init__.py' (properties changed: +x to -x) |
2 | --- PyngPyng/__init__.py 2009-05-24 23:57:05 +0000 |
3 | +++ PyngPyng/__init__.py 2009-05-26 02:25:17 +0000 |
4 | @@ -16,6 +16,7 @@ |
5 | |
6 | # Extension modules ----------------------------------------------------------- |
7 | from PyngPyng.pages import Page, ErrorPage |
8 | +from PyngPyng import exceptions as exc |
9 | from PyngPyng import version |
10 | |
11 | # Module function ------------------------------------------------------------- |
12 | @@ -53,9 +54,9 @@ |
13 | # Run the requested page |
14 | try: |
15 | page = Page(environ) |
16 | - page.parse_request() |
17 | - page.execute() |
18 | - page.composite() |
19 | + page.do_it() |
20 | + if not page.content: |
21 | + raise exc.NoContentException('Expected page content to be generated. Perhaps the page compositor has not been implemented?') |
22 | start_response(page.status,page.headers) |
23 | return page.content |
24 | except: |
25 | |
26 | === modified file 'PyngPyng/exceptions.py' |
27 | --- PyngPyng/exceptions.py 2009-05-25 03:11:31 +0000 |
28 | +++ PyngPyng/exceptions.py 2009-05-26 02:09:15 +0000 |
29 | @@ -14,6 +14,12 @@ |
30 | # Exception class ------------------------------------------------------------- |
31 | class Pyngception(Exception): |
32 | """An internal PyngPyng exception occured.""" |
33 | + http_code = '500 Internal Server Error' |
34 | + |
35 | + |
36 | +# Exception class ------------------------------------------------------------- |
37 | +class NoContentException(Pyngception): |
38 | + """The page content is empty or None.""" |
39 | pass |
40 | |
41 | |
42 | |
43 | === modified file 'PyngPyng/pages.py' |
44 | --- PyngPyng/pages.py 2009-05-25 03:11:31 +0000 |
45 | +++ PyngPyng/pages.py 2009-05-26 02:25:17 +0000 |
46 | @@ -12,22 +12,58 @@ |
47 | |
48 | # Extension modules ----------------------------------------------------------- |
49 | from PyngPyng import version |
50 | +from PyngPyng import exceptions as exc |
51 | + |
52 | +# Class factory --------------------------------------------------------------- |
53 | +def Page(environ): |
54 | + """ |
55 | + Create a Page object (of appropriate subclass) based on the request URI. |
56 | + |
57 | + Parameters |
58 | + ---------- |
59 | + environ : dict |
60 | + The WSGI environment variable is a dictionary object containing CGI- |
61 | + style environment variables. See PEP333 for specification. It also |
62 | + contains the pre-parsed URI and ARGS parameters. |
63 | + |
64 | + Returns |
65 | + ------- |
66 | + page : PageBase |
67 | + The PageBase (or PageBase-subclass) object associated with the request. |
68 | + |
69 | + """ |
70 | + pagename = environ['URI'][0] |
71 | + if pagename == '': # we are at the application root |
72 | + return RootPage(environ) |
73 | + elif pagename == 'rules': # we are at the rules static-ish page |
74 | + return RulesPage(environ) |
75 | + elif pagename == 'retired': # we are looking at retired players |
76 | + return RetiredPage(environ) |
77 | + elif pagename == '+game': # we are adding a game |
78 | + return GameAction(environ) |
79 | + elif pagename == '+user': # we are adding a user |
80 | + return UserAction(environ) |
81 | + elif pagename == '+retire': # we are retiring a user |
82 | + return RetireAction(environ) |
83 | + else: # we expect uri[0] to be a {username} |
84 | + return FilterPage(environ) |
85 | |
86 | |
87 | # Module class ---------------------------------------------------------------- |
88 | -class Page(object): |
89 | +class PageBase(object): |
90 | |
91 | """ |
92 | - A Page object is resonsible for processing content, applying themes, and |
93 | - returning the XHTML to the user via HTTP. |
94 | + A PageBase object is resonsible for processing content, applying themes, |
95 | + and returning the XHTML to the user via HTTP. This is a base class that |
96 | + should be subclassed for specific functionality. |
97 | |
98 | """ |
99 | |
100 | # Class initializer ------------------------------------------------------- |
101 | def __init__(self,environ): |
102 | """ |
103 | - Initialize the Page instance. This is a lean operation in that the page |
104 | - content is not generated until required. |
105 | + Initialize the PageBase instance. This is a lean operation in that the |
106 | + page content is not generated until required. |
107 | |
108 | Parameters |
109 | ---------- |
110 | @@ -44,13 +80,17 @@ |
111 | # Set status and headers (assume OK; if not, these will get changed) |
112 | self.status = '200 OK' |
113 | self.headers = [('Content-Type','text/html')] |
114 | - self.template = 'PyngPyng/templates/pyng.page' |
115 | + self.template = 'PyngPyng/templates/pyng.tpl' |
116 | # Copy environment parameters |
117 | self.script_name = environ.get('SCRIPT_NAME','') |
118 | self.request_method = environ.get('REQUEST_METHOD',None) |
119 | - self.args = environ.get('ARGS',None) |
120 | - self.uri = environ.get('URI',None) |
121 | + self.args = environ['ARGS'] # If args or uri are not set, something is messed up |
122 | + self.uri = environ['URI'] |
123 | # Set initial page attributes |
124 | + self.template_parameters = { |
125 | + 'uri' : self.uri |
126 | + } |
127 | + self.is_action = False |
128 | self.is_composited = False |
129 | self.content = None |
130 | self.page = None |
131 | @@ -70,8 +110,11 @@ |
132 | None |
133 | |
134 | """ |
135 | - pass |
136 | - |
137 | + if self.request_method == 'POST' and not self.is_action: |
138 | + raise exc.HTTPMethodNotAllowedError('POST methods are only allowed for ''action'' resources, indicated by a ''+''.') |
139 | + elif self.request_method != 'GET': |
140 | + raise exc.HTTPMethodNotAllowedError('Only GET and POST methods are allowed at this time; POST methods are only allowed on ''action'' resources, indicated by a ''+''.') |
141 | + |
142 | # Class function ---------------------------------------------------------- |
143 | def execute(self): |
144 | """ |
145 | @@ -106,23 +149,66 @@ |
146 | None |
147 | |
148 | """ |
149 | - self.page = '\n'.join([ |
150 | - 'Hello, world!', |
151 | - 'How are you today?', |
152 | - 'I am fine, thank you!' |
153 | - ]) |
154 | - template_parameters = { |
155 | - 'title' : 'PyngPyng games ladder', |
156 | - 'page' : self.page, |
157 | - 'uri' : self.uri |
158 | - } |
159 | + pass |
160 | + |
161 | + # Class function ---------------------------------------------------------- |
162 | + def do_it(self): |
163 | + self.parse_request() |
164 | + self.execute() |
165 | + self.composite() |
166 | + |
167 | + |
168 | +# Module class ---------------------------------------------------------------- |
169 | +class ActionBase(PageBase): |
170 | + def __init__(self,environ): |
171 | + PageBase.__init__(self,environ) |
172 | + self.is_action = self.request_method == 'POST' |
173 | + |
174 | + |
175 | +# Module class ---------------------------------------------------------------- |
176 | +class RootPage(PageBase): |
177 | + pass |
178 | + |
179 | + |
180 | +# Module class ---------------------------------------------------------------- |
181 | +class RulesPage(PageBase): |
182 | + def composite(self): |
183 | + self.template_parameters['title'] = 'PyngPyng games ladder' |
184 | + with open('PyngPyng/templates/rules.page','r') as rules: |
185 | + self.page = rules.read() |
186 | with open(self.template,'r') as template: |
187 | - self.content = template.read() % template_parameters |
188 | + self.template_parameters['page'] = self.page |
189 | + self.content = template.read() % self.template_parameters |
190 | self.is_composited = True |
191 | |
192 | |
193 | # Module class ---------------------------------------------------------------- |
194 | -class ErrorPage(Page): |
195 | +class RetiredPage(PageBase): |
196 | + pass |
197 | + |
198 | + |
199 | +# Module class ---------------------------------------------------------------- |
200 | +class GameAction(ActionBase): |
201 | + pass |
202 | + |
203 | + |
204 | +# Module class ---------------------------------------------------------------- |
205 | +class UserAction(ActionBase): |
206 | + pass |
207 | + |
208 | + |
209 | +# Module class ---------------------------------------------------------------- |
210 | +class RetireAction(ActionBase): |
211 | + pass |
212 | + |
213 | + |
214 | +# Module class ---------------------------------------------------------------- |
215 | +class FilterPage(PageBase): |
216 | + pass |
217 | + |
218 | + |
219 | +# Module class ---------------------------------------------------------------- |
220 | +class ErrorPage(PageBase): |
221 | |
222 | """ |
223 | An ErrorPage object is responsible for reporting application errors to the |
224 | @@ -133,14 +219,26 @@ |
225 | # Class function ---------------------------------------------------------- |
226 | def __init__(self,environ,exc_info): |
227 | """ |
228 | - Initialize the ErrorPage instance. |
229 | + Initialize the ErrorPage instance. This is generates the output |
230 | + immediately. |
231 | + |
232 | + Parameters |
233 | + ---------- |
234 | + environ : dict |
235 | + The WSGI environment variable is a dictionary object containing CGI- |
236 | + style environment variables. See PEP333 for specification. It also |
237 | + contains the pre-parsed URI and ARGS parameters. |
238 | + |
239 | + Returns |
240 | + ------- |
241 | + None |
242 | |
243 | """ |
244 | import traceback |
245 | - Page.__init__(self,environ) |
246 | + PageBase.__init__(self,environ) |
247 | # Copy exception information |
248 | self.etype, self.evalue, self.etrace = exc_info |
249 | - self.template = 'PyngPyng/templates/error.page' |
250 | + self.template = 'PyngPyng/templates/error.tpl' |
251 | # Set default error status and headers (can be changed later to |
252 | # customize for particular error conditions) |
253 | try: |
254 | |
255 | === removed file 'PyngPyng/templates/error.page' |
256 | --- PyngPyng/templates/error.page 2009-05-24 19:57:14 +0000 |
257 | +++ PyngPyng/templates/error.page 1970-01-01 00:00:00 +0000 |
258 | @@ -1,34 +0,0 @@ |
259 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> |
260 | - |
261 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
262 | -<head profile="http://gmpg.org/xfn/11"> |
263 | - <meta http-equiv="Content-Type" content="text/xhtml; charset=UTF-8" /> |
264 | - <meta name="robots" content="none" /> |
265 | - <title>%(title)s</title> |
266 | - <style type="text/css"> |
267 | - body { font-family:Verdana; font-size:10pt; } |
268 | - h1 { font-weight:normal; font-size:18pt; color:red; } |
269 | - h2 { font-weight:normal; font-style:italic; font-size:14pt; color:maroon; } |
270 | - div#trace { background-color:#FFFFCC; margin-top:-0.75em; } |
271 | - div#version { color:gray; } |
272 | - </style> |
273 | -</head> |
274 | - |
275 | -<body> |
276 | - <h1>Server Error at '%(request_uri)s' in %(app_name)s.</h1> |
277 | - <hr width="100%%" size=1 color="silver" /> |
278 | - <h2>%(exc_type)s » %(exc_details)s</h2> |
279 | - |
280 | - <b>Description:</b> %(exc_description)s<br/><br/> |
281 | - <b>Exception Details:</b> %(exc_type)s: %(exc_details)s<br/><br/> |
282 | - |
283 | - <b>Stack Trace:</b> |
284 | - <div id="trace"> |
285 | - <code><pre>%(exc_trace)s</code></pre> |
286 | - </div> |
287 | - <hr width="100%%" size=1 color="silver" /> |
288 | - <div id="version"> |
289 | - <b>Version Information:</b> %(version)s |
290 | - </div> |
291 | -</body> |
292 | -</html> |
293 | |
294 | === added file 'PyngPyng/templates/error.tpl' |
295 | --- PyngPyng/templates/error.tpl 1970-01-01 00:00:00 +0000 |
296 | +++ PyngPyng/templates/error.tpl 2009-05-25 18:49:00 +0000 |
297 | @@ -0,0 +1,34 @@ |
298 | +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> |
299 | + |
300 | +<html xmlns="http://www.w3.org/1999/xhtml"> |
301 | +<head profile="http://gmpg.org/xfn/11"> |
302 | + <meta http-equiv="Content-Type" content="text/xhtml; charset=UTF-8" /> |
303 | + <meta name="robots" content="none" /> |
304 | + <title>%(title)s</title> |
305 | + <style type="text/css"> |
306 | + body { font-family:Verdana; font-size:10pt; } |
307 | + h1 { font-weight:normal; font-size:18pt; color:red; } |
308 | + h2 { font-weight:normal; font-style:italic; font-size:14pt; color:maroon; } |
309 | + div#trace { background-color:#FFFFCC; margin-top:-0.75em; } |
310 | + div#version { color:gray; } |
311 | + </style> |
312 | +</head> |
313 | + |
314 | +<body> |
315 | + <h1>Server Error at '%(request_uri)s' in %(app_name)s.</h1> |
316 | + <hr width="100%%" size=1 color="silver" /> |
317 | + <h2>%(exc_type)s » %(exc_details)s</h2> |
318 | + |
319 | + <b>Description:</b> %(exc_description)s<br/><br/> |
320 | + <b>Exception Details:</b> %(exc_type)s: %(exc_details)s<br/><br/> |
321 | + |
322 | + <b>Stack Trace:</b> |
323 | + <div id="trace"> |
324 | + <code><pre>%(exc_trace)s</code></pre> |
325 | + </div> |
326 | + <hr width="100%%" size=1 color="silver" /> |
327 | + <div id="version"> |
328 | + <b>Version Information:</b> %(version)s |
329 | + </div> |
330 | +</body> |
331 | +</html> |
332 | |
333 | === removed file 'PyngPyng/templates/pyng.page' |
334 | --- PyngPyng/templates/pyng.page 2009-05-25 03:11:31 +0000 |
335 | +++ PyngPyng/templates/pyng.page 1970-01-01 00:00:00 +0000 |
336 | @@ -1,24 +0,0 @@ |
337 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> |
338 | - |
339 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
340 | -<head profile="http://gmpg.org/xfn/11"> |
341 | - <meta http-equiv="Content-Type" content="text/xhtml; charset=UTF-8" /> |
342 | - <meta name="distribution" content="global" /> |
343 | - <meta name="robots" content="index,follow" /> |
344 | - <meta name="language" content="en, sv" /> |
345 | - <title>%(title)s</title> |
346 | - <!--<link rel="stylesheet" type="text/css" charset="utf-8" media="all" href="http://localhost:8080/static/default.css" />--> |
347 | -</head> |
348 | - |
349 | -<body> |
350 | - <div id="header"> |
351 | - %(uri)s |
352 | - </div> |
353 | - <div id="page"> |
354 | - %(page)s |
355 | - </div> |
356 | - <div id="footer"> |
357 | - <div id="xhtml">Valid <a href="http://validator.w3.org/check/referer">XHTML</a> and <a href="http://jigsaw.w3.org/css-validator/check/referer">CSS</a></div> |
358 | - </div> |
359 | -</body> |
360 | -</html> |
361 | |
362 | === added file 'PyngPyng/templates/pyng.tpl' |
363 | --- PyngPyng/templates/pyng.tpl 1970-01-01 00:00:00 +0000 |
364 | +++ PyngPyng/templates/pyng.tpl 2009-05-25 18:49:00 +0000 |
365 | @@ -0,0 +1,24 @@ |
366 | +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> |
367 | + |
368 | +<html xmlns="http://www.w3.org/1999/xhtml"> |
369 | +<head profile="http://gmpg.org/xfn/11"> |
370 | + <meta http-equiv="Content-Type" content="text/xhtml; charset=UTF-8" /> |
371 | + <meta name="distribution" content="global" /> |
372 | + <meta name="robots" content="index,follow" /> |
373 | + <meta name="language" content="en, sv" /> |
374 | + <title>%(title)s</title> |
375 | + <!--<link rel="stylesheet" type="text/css" charset="utf-8" media="all" href="http://localhost:8080/static/default.css" />--> |
376 | +</head> |
377 | + |
378 | +<body> |
379 | + <div id="header"> |
380 | + %(uri)s |
381 | + </div> |
382 | + <div id="page"> |
383 | + %(page)s |
384 | + </div> |
385 | + <div id="footer"> |
386 | + <div id="xhtml">Valid <a href="http://validator.w3.org/check/referer">XHTML</a> and <a href="http://jigsaw.w3.org/css-validator/check/referer">CSS</a></div> |
387 | + </div> |
388 | +</body> |
389 | +</html> |
390 | |
391 | === added file 'PyngPyng/templates/rules.page' |
392 | --- PyngPyng/templates/rules.page 1970-01-01 00:00:00 +0000 |
393 | +++ PyngPyng/templates/rules.page 2009-05-25 18:49:00 +0000 |
394 | @@ -0,0 +1,13 @@ |
395 | +<ol id="rules"> |
396 | + <li>All matches are to be best of three games.</li> |
397 | + <li>All games are to be played to 21 points.</li> |
398 | + <li>A game weighting is to be decided on before the game. It must be an integer from 1 to 10 (inclusive).</li> |
399 | + <li>The higher the weight of the game the more points the winners can win (and the losers can lose).</li> |
400 | + <li>If no game weight is chosen, the default game weight is 4.</li> |
401 | + <li>Both singles and doubles games count towards the SFL Ping Pong ladder.</li> |
402 | + <li>We salute those SFL Ping Pongers that have come before us.</li> |
403 | + <li>By default assume that Grant is cheating and take appropriate action.</li> |
404 | + <li>Let Mark win sometimes, his score is pathetic.</li> |
405 | + <li>Honour Chris for creating this magical software.</li> |
406 | + <li>If Guy is going to smash, for safety's sake get as close to the table as possible, because the ball is not going anywhere near it.</li> |
407 | +</ol> |
408 | |
409 | === modified file 'PyngPyng/version.py' (properties changed: -x to +x) |
410 | --- PyngPyng/version.py 2009-05-24 23:57:05 +0000 |
411 | +++ PyngPyng/version.py 2009-05-25 12:12:54 +0000 |
412 | @@ -10,7 +10,7 @@ |
413 | # Version information --------------------------------------------------------- |
414 | project = 'PyngPyng' |
415 | release = '0' |
416 | -revision = 'lp:pyng (trunk)' |
417 | +revision = 'lp:~scott-armitage/pyng/uri-pattern' |
418 | agent = ' '.join((project,release,revision)) |
419 | |
420 | # Script body ----------------------------------------------------------------- |