import webob.exc from repoze.bfg.configuration import Configurator from repoze.bfg.url import route_url from repoze.bfg.threadlocal import get_current_request from repoze.bfg.exceptions import NotFound from repoze.bfg.exceptions import Forbidden from repoze.bfg.view import AppendSlashNotFoundViewFactory from repoze.bfg.view import append_slash_notfound_view from repoze.bfg.renderers import render from beaker.middleware import SessionMiddleware from repoze.bfg.jinja2.bindings import renderer_factory as jinja2_renderer from paste.httpserver import serve from weberror.evalexception import EvalException class Namespace(object): pass class Groundhog(object): def __init__(self, package, session_key): self.package = package self.session_key = session_key self.g = Namespace() self.config = Configurator() self.config.begin() self.config.add_renderer('groundhog', self.renderer_factory) self.config.add_renderer('.html', jinja2_renderer) self.config.set_renderer_globals_factory(self.renderer_globals_factory) self.config.add_view(append_slash_notfound_view, context=NotFound) self.config.add_view(self.handle_webob_exc, context=webob.exc.WSGIHTTPException) self.config.add_static_view('static', '%s:static' % self.package) def handle_webob_exc(self, exc, request): return request.get_response(exc) def renderer_factory(self, name): def render_(value, system): request = system.get('request') if request is not None: request.response_content_type = 'text/html' return value return render_ def renderer_globals_factory(self, system): return {'g':self.g, 'app':self} def mapply(self, func): def mapplied(request): return func(**request.matchdict) return mapplied def route(self, pattern, methods=('GET', 'HEAD')): def decorator(func): endpoint = func.__name__ self.config.add_route(endpoint, pattern) for method in methods: view = self.mapply(func) self.config.add_view(view, route_name=endpoint, request_method=method, renderer='groundhog') return func return decorator def run(self, host=None, port=8080, debug=False): self.config.end() app = self.config.make_wsgi_app() if debug: app = EvalException(app) session_options = { 'session.type':'cookie', 'session.cookie_expires':True, 'session.auto':True, 'session.validate_key':self.session_key, } app = SessionMiddleware(app, session_options) serve(app, host, port) def url_for(self, endpoint, *arg, **options): if not isinstance(endpoint, basestring): endpoint = endpoint.__name__ request = self.request return route_url(endpoint, request, *arg, **options) @property def request(self): return get_current_request() @property def session(self): return self.request.environ['beaker.session'] def flash(self, message): session = self.session fq = session.setdefault('flash_queue', []) fq.append(message) session.save() def get_flashed_messages(self): session = self.session result = session.pop('flash_queue', []) session.save() return result def render_template(self, name, **kw): request = self.request return render('%s:templates/%s' % (self.package, name), request=request, **kw) def abort(self, code, message=''): raise webob.exc.status_map[code](message) def redirect(self, url): raise webob.exc.HTTPFound(location=url) def errorhandler(self, code): bfg_status_map = {404:NotFound, 401:Forbidden} def decorator(func): def errfunc(exc, request): request.response_status = exc.status return func(exc) webob_exc = webob.exc.status_map.get(code) bfg_exc = bfg_status_map.get(code) for exc in (webob_exc, bfg_exc): if exc is not None: view = errfunc if exc is NotFound: view = AppendSlashNotFoundViewFactory(errfunc) self.config.add_view(view, context=exc, renderer='groundhog') return decorator # application app = Groundhog(__name__, 'seekrit') @app.route('/') def root(): return 'root' @app.route('/exc/:code') def exc(code=404): code = int(code) app.abort(code, 'this is the message') @app.route('/redir') def redir(): app.redirect('/') @app.errorhandler(404) def handle_404(exc): return 'not found, yo' @app.errorhandler(500) def handle_500(exc): return 'its broke' if __name__ == '__main__': app.run(debug=True)