Merge lp:~scott-armitage/pyng/uri-pattern into lp:pyng

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
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.

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 &raquo; %(exc_details)s</h2>
279-
280- <b>Description:</b>&nbsp;%(exc_description)s<br/><br/>
281- <b>Exception Details:</b>&nbsp;%(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>&nbsp;%(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 &raquo; %(exc_details)s</h2>
318+
319+ <b>Description:</b>&nbsp;%(exc_description)s<br/><br/>
320+ <b>Exception Details:</b>&nbsp;%(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>&nbsp;%(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 -----------------------------------------------------------------

Subscribers

People subscribed via source and target branches

to all changes: