diff --git a/pecan/__init__.py b/pecan/__init__.py index 9538339..bfef5b0 100644 --- a/pecan/__init__.py +++ b/pecan/__init__.py @@ -1,7 +1,9 @@ from paste.urlparser import StaticURLParser from paste.cascade import Cascade +from weberror.errormiddleware import ErrorMiddleware +from paste.recursive import RecursiveMiddleware -from pecan import Pecan, request, response, override_template, redirect +from pecan import Pecan, request, response, override_template, redirect, error_for from decorators import expose __all__ = [ @@ -9,8 +11,10 @@ __all__ = [ ] -def make_app(root, static_root=None, **kw): +def make_app(root, static_root=None, debug=False, errorcfg={}, **kw): app = Pecan(root, **kw) + app = RecursiveMiddleware(app) + app = ErrorMiddleware(app, debug=debug, **errorcfg) if static_root: app = Cascade([StaticURLParser(static_root), app]) return app \ No newline at end of file diff --git a/pecan/pecan.py b/pecan/pecan.py index ec4fa0d..e2a4755 100644 --- a/pecan/pecan.py +++ b/pecan/pecan.py @@ -5,6 +5,7 @@ from webob import Request, Response, exc from threading import local from itertools import chain from formencode import Invalid +from paste.recursive import ForwardRequestException try: from json import loads @@ -19,6 +20,8 @@ def proxy(key): class ObjectProxy(object): def __getattr__(self, attr): obj = getattr(state, key) + if attr == 'validation_error': + return getattr(obj, attr, None) return getattr(obj, attr) def __setattr__(self, attr, value): obj = getattr(state, key) @@ -37,6 +40,10 @@ def override_template(template): def redirect(location): raise exc.HTTPFound(location=location) +def error_for(field): + if request.validation_error is None: return '' + return request.validation_error.error_dict.get(field, '') + class Pecan(object): def __init__(self, root, @@ -122,6 +129,7 @@ class Pecan(object): controller.pecan['argspec'] ) if 'schema' in controller.pecan: + request.validation_error = None try: params = self.validate( controller.pecan['schema'], @@ -131,8 +139,7 @@ class Pecan(object): except Invalid, e: request.validation_error = e if controller.pecan['error_handler'] is not None: - state.validation_error = e - redirect(controller.pecan['error_handler']) + raise ForwardRequestException(controller.pecan['error_handler']) if controller.pecan['validate_json']: params = dict(data=params) # get the result from the controller @@ -147,7 +154,10 @@ class Pecan(object): renderer = self.renderers.get(self.default_renderer, self.template_path) if template == 'json': renderer = self.renderers.get('json', self.template_path) - elif ':' in template: + else: + result['error_for'] = error_for + + if ':' in template: renderer = self.renderers.get(template.split(':')[0], self.template_path) template = template.split(':')[1] result = renderer.render(template, result) @@ -168,12 +178,7 @@ class Pecan(object): state.request = Request(environ) state.response = Response() state.hooks = [] - - # handle validation errors from redirects - if hasattr(state, 'validation_error'): - state.request.validation_error = state.validation_error - del state.validation_error - + # handle the request try: self.handle_request() diff --git a/setup.py b/setup.py index e1cf968..0e23117 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,8 @@ class PyTest(Command): # determine requirements # requirements = [ - "WebOb >= 0.9.8", + "WebOb >= 1.0.0", + "WebCore >= 1.0.0", "simplegeneric >= 0.7", "Genshi >= 0.6", "Kajiki >= 0.2.2", diff --git a/templates/project/+egg+/controllers/root.py b/templates/project/+egg+/controllers/root.py index 5c404e1..f5c5ae9 100644 --- a/templates/project/+egg+/controllers/root.py +++ b/templates/project/+egg+/controllers/root.py @@ -1,6 +1,17 @@ -from pecan import expose +from pecan import expose, request +from formencode import Schema, validators as v + + +class SampleForm(Schema): + name = v.String(not_empty=True) + age = v.Int(not_empty=True) + class RootController(object): @expose('kajiki:index.html') - def index(self, name='World'): - return dict(name=name) \ No newline at end of file + def index(self, name='', age=''): + return dict(errors=request.validation_error, name=name, age=age) + + @expose('kajiki:success.html', schema=SampleForm(), error_handler='index') + def handle_form(self, name, age): + return dict(name=name, age=age) diff --git a/templates/project/+egg+/templates/index.html b/templates/project/+egg+/templates/index.html index d2a8837..2411552 100644 --- a/templates/project/+egg+/templates/index.html +++ b/templates/project/+egg+/templates/index.html @@ -1,8 +1,44 @@ - + - Hello, ${name} + Welcome to Pecan! - -

Hello, ${name}!

+ +
+

Welcome to Pecan

+
+

This is the default Pecan project, which includes:

+ + + +

+ Note that most functionality is enabled/disabled in your start.py, + which can be edited to suit your needs, and to add additional WSGI middleware. +

+ +

+ To get an idea of how to develop applications with Pecan, + here is a simple form: +

+ +
+ + + + + + + + + + + +
${error_for('name')}
${error_for('age')}
+ + +
\ No newline at end of file diff --git a/templates/project/+egg+/templates/layout.html b/templates/project/+egg+/templates/layout.html new file mode 100644 index 0000000..7cf7c06 --- /dev/null +++ b/templates/project/+egg+/templates/layout.html @@ -0,0 +1,13 @@ + + + Default Title + + + + +