From 1bc441876ba13a3ef1b07cbead8d3b9e29a5fabf Mon Sep 17 00:00:00 2001 From: Jonathan LaCour Date: Mon, 11 Oct 2010 08:54:51 -0400 Subject: [PATCH] A few minor tweaks: * Only require simplejson if we need to. * Improve upon parameter validation. * Add a redirect utility function. * Remove some print statements. --- pecan/__init__.py | 2 +- pecan/decorators.py | 8 ++++++++ pecan/pecan.py | 19 +++++++++++++++++-- pecan/templating.py | 4 ---- setup.py | 41 +++++++++++++++++++++++++++-------------- tests/test_base.py | 36 ++++++++++++++++++++++++++++++++++-- 6 files changed, 87 insertions(+), 23 deletions(-) diff --git a/pecan/__init__.py b/pecan/__init__.py index 165eb85..9538339 100644 --- a/pecan/__init__.py +++ b/pecan/__init__.py @@ -1,7 +1,7 @@ from paste.urlparser import StaticURLParser from paste.cascade import Cascade -from pecan import Pecan, request, response, override_template +from pecan import Pecan, request, response, override_template, redirect from decorators import expose __all__ = [ diff --git a/pecan/decorators.py b/pecan/decorators.py index 699df8d..8927702 100644 --- a/pecan/decorators.py +++ b/pecan/decorators.py @@ -1,10 +1,18 @@ +from inspect import getargspec + def expose(template=None, content_type='text/html'): if template == 'json': content_type = 'application/json' def decorate(f): + # flag the method as exposed f.exposed = True + + # set a "pecan" attribute, where we will store details if not hasattr(f, 'pecan'): f.pecan = {} f.pecan['content_type'] = content_type f.pecan.setdefault('template', []).append(template) f.pecan.setdefault('content_types', {})[content_type] = template + + # store the arguments for this controller method + f.pecan['argspec'] = getargspec(f) return f return decorate \ No newline at end of file diff --git a/pecan/pecan.py b/pecan/pecan.py index 4e421d3..6ec2892 100644 --- a/pecan/pecan.py +++ b/pecan/pecan.py @@ -28,6 +28,10 @@ def override_template(template): request.override_template = template +def redirect(location): + raise exc.HTTPFound(location=location) + + class Pecan(object): def __init__(self, root, renderers = renderers, @@ -70,6 +74,13 @@ class Pecan(object): for hook in state.hooks: getattr(hook, hook_type)(*args) + def get_validated_params(self, all_params, argspec): + valid_params = dict() + for param_name, param_value in all_params.iteritems(): + if param_name in argspec.args: + valid_params[param_name] = param_value + return valid_params + def handle_request(self): # lookup the controller, respecting content-type as requested # by the file extension on the URI @@ -94,8 +105,12 @@ class Pecan(object): self.handle_hooks('before', state) # get the result from the controller, properly handling wrap hooks - result = controller(**dict(state.request.str_params)) - + params = self.get_validated_params( + dict(state.request.str_params), + controller.pecan['argspec'] + ) + result = controller(**params) + # pull the template out based upon content type and handle overrides template = controller.pecan.get('content_types', {}).get(content_type) template = getattr(request, 'override_template', template) diff --git a/pecan/templating.py b/pecan/templating.py index 9f6a4c3..47776f0 100644 --- a/pecan/templating.py +++ b/pecan/templating.py @@ -35,10 +35,6 @@ class JsonRenderer(object): def render(self, template_path, namespace): from jsonify import encode result = encode(namespace) - print '*' * 80 - print result - print type(result) - print '*' * 80 return result diff --git a/setup.py b/setup.py index 27f1fa6..a9b4fc5 100644 --- a/setup.py +++ b/setup.py @@ -17,10 +17,34 @@ class PyTest(Command): py.cmdline.pytest(py.std.sys.argv[2:]) +# +# determine requirements +# +requirements = [ + "WebOb >= 0.9.8", + "simplegeneric >= 0.7", + "Genshi >= 0.6", + "Kajiki >= 0.2.2", + "Mako >= 0.3", + "py >= 1.3.4", + "WebTest >= 1.2.2", + "Paste >= 1.7.5.1", + "PasteScript >= 1.7.3" +] + +try: + import json +except: + requirements.append("simplejson >= 2.1.1") + + +# +# call setup +# setup( name = 'pecan', version = version, - description = "A WSGI object-dispatching web framework, in the spirit of TurboGears, only much much smaller, with many fewer dependancies.", + description = "A WSGI object-dispatching web framework, in the spirit of TurboGears, only much much smaller, with many fewer dependencies.", long_description = None, classifiers = [], keywords = '', @@ -32,19 +56,8 @@ setup( include_package_data = True, zip_safe = True, cmdclass = {'test': PyTest}, - install_requires=[ - "WebOb >= 0.9.8", - "simplegeneric >= 0.7", - "Genshi >= 0.6", - "Kajiki >= 0.2.2", - "Mako >= 0.3", - "py >= 1.3.4", - "WebTest >= 1.2.2", - "Paste >= 1.7.5.1", - "simplejson >= 2.1.1", - "PasteScript >= 1.7.3" - ], - entry_points = """ + install_requires = requirements, + entry_points = """ [paste.paster_create_template] pecan-base = templates:NewProjectTemplate """, diff --git a/tests/test_base.py b/tests/test_base.py index 81056c2..64f0c43 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -1,4 +1,4 @@ -from pecan import Pecan, expose, request, response +from pecan import Pecan, expose, request, response, redirect from webtest import TestApp class TestBase(object): @@ -160,4 +160,36 @@ class TestEngines(object): r = app.get('/') assert r.status_int == 200 result = dict(loads(r.body)) - assert result == expected_result \ No newline at end of file + assert result == expected_result + + def test_controller_parameters(self): + class RootController(object): + @expose('json') + def index(self, argument=None): + assert argument == 'value' + + # arguments should get passed appropriately + app = TestApp(Pecan(RootController())) + r = app.get('/?argument=value') + assert r.status_int == 200 + + # extra arguments get stripped off + r = app.get('/?argument=value&extra=not') + assert r.status_int == 200 + + def test_redirect(self): + class RootController(object): + @expose() + def index(self): + redirect('/testing') + + @expose() + def testing(self): + return 'it worked!' + + app = TestApp(Pecan(RootController())) + r = app.get('/') + assert r.status_int == 302 + r = r.follow() + assert r.status_int == 200 + assert r.body == 'it worked!' \ No newline at end of file