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.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_static_view('static', '%s:static' % self.package) 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) # application app = Groundhog(__name__, 'seekrit') app.g.foo = 1 @app.route('/') def aview(): return ('foo 1' % app.url_for('foo', id='1', _anchor='fudge')) @app.route('/foo/:id') def foo(id=None): return '%s' % id @app.route('/slashending/') def slashending(): return 'ends in a slash' @app.route('/exception') def exc(): raise RuntimeError('exception view') @app.route('/templated') def templated(): return app.render_template('template.html', project='groundhog') @app.route('/zpt_templated') def zpt_templated(): return app.render_template('template.pt', project='groundhog') @app.route('/add_flash_message/:message') def add_flash_message(message=None): app.flash(message) return message if __name__ == '__main__': app.run(debug=True)