class Brick(object): def __init__(self, catchall=True, autojson=True, config=None): self.routes = Router() self._logger = None self.mounts = {} self.error_handler = {} self.catchall = catchall self.config = config or {} self.serve = True self.castfilter = [] if autojson and dumps: self.add_filter(dict, dumps) def optimize(self, *a, **ka): depr("Brick.optimize() is obsolete.") def mount(self, app, script_path): if not isinstance(app, Brick): raise TypeError('Only Brick instances are supported for now.') script_path = '/'.join(filter(None, script_path.split('/'))) path_depth = script_path.count('/') + 1 if not script_path: raise TypeError('Empty script_path. Perhaps you want a merge()?') for other in self.mounts: if other.startswith(script_path): raise TypeError('Conflict with existing mount: %s' % other) @self.route('/%s/:#.*#' % script_path, method="ANY") def mountpoint(): request.path_shift(path_depth) return app.handle(request.path, request.method) self.mounts[script_path] = app def add_filter(self, ftype, func): if not isinstance(ftype, type): raise TypeError("Expected type object, got %s" % type(ftype)) self.castfilter = [(t, f) for (t, f) in self.castfilter if t != ftype] self.castfilter.append((ftype, func)) self.castfilter.sort() def match_url(self, path, method='GET'): path, method = path.strip().lstrip('/'), method.upper() callbacks, args = self.routes.match(path) if not callbacks: raise HTTPError(404, "Not found: " + path) if method in callbacks: return callbacks[method], args if method == 'HEAD' and 'GET' in callbacks: return callbacks['GET'], args if 'ANY' in callbacks: return callbacks['ANY'], args allow = [m for m in callbacks if m != 'ANY'] if 'GET' in allow and 'HEAD' not in allow: allow.append('HEAD') raise HTTPError(405, "Method not allowed.", header=[('Allow', ",".join(allow))]) def get_url(self, routename, **kargs): scriptname = request.environ.get('SCRIPT_NAME', '').strip('/') + '/' location = self.routes.build(routename, **kargs).lstrip('/') return urljoin(urljoin('/', scriptname), location) def route(self, path=None, method='GET', **kargs): def wrapper(callback): routes = [path] if path else yieldroutes(callback) methods = method.split(';') if isinstance(method, str) else method for r in routes: for m in methods: r, m = r.strip().lstrip('/'), m.strip().upper() old = self.routes.get_route(r, **kargs) if old: old.target[m] = callback else: self.routes.add(r, {m: callback}, **kargs) self.routes.compile() return callback return wrapper def get(self, path=None, method='GET', **kargs): return self.route(path, method, **kargs) def post(self, path=None, method='POST', **kargs): return self.route(path, method, **kargs) def put(self, path=None, method='PUT', **kargs): return self.route(path, method, **kargs) def delete(self, path=None, method='DELETE', **kargs): return self.route(path, method, **kargs) def error(self, code=500): def wrapper(handler): self.error_handler[int(code)] = handler return handler return wrapper def handle(self, url, method): if not self.serve: return HTTPError(503, "Server stopped") try: handler, args = self.match_url(url, method) return handler(**args) except HTTPResponse, e: return e except Exception, e: if isinstance(e, (KeyboardInterrupt, SystemExit, MemoryError))\ or not self.catchall: raise print e return HTTPError(500, 'Unhandled exception', e, format_exc(10))
class Brick(object): def __init__(self, catchall=True, autojson=True, config=None): self.routes = Router() self._logger=None self.mounts = {} self.error_handler = {} self.catchall = catchall self.config = config or {} self.serve = True self.castfilter = [] if autojson and dumps: self.add_filter(dict, dumps) def optimize(self, *a, **ka): depr("Brick.optimize() is obsolete.") def mount(self, app, script_path): if not isinstance(app, Brick): raise TypeError('Only Brick instances are supported for now.') script_path = '/'.join(filter(None, script_path.split('/'))) path_depth = script_path.count('/') + 1 if not script_path: raise TypeError('Empty script_path. Perhaps you want a merge()?') for other in self.mounts: if other.startswith(script_path): raise TypeError('Conflict with existing mount: %s' % other) @self.route('/%s/:#.*#' % script_path, method="ANY") def mountpoint(): request.path_shift(path_depth) return app.handle(request.path, request.method) self.mounts[script_path] = app def add_filter(self, ftype, func): if not isinstance(ftype, type): raise TypeError("Expected type object, got %s" % type(ftype)) self.castfilter = [(t, f) for (t, f) in self.castfilter if t != ftype] self.castfilter.append((ftype, func)) self.castfilter.sort() def match_url(self, path, method='GET'): path, method = path.strip().lstrip('/'), method.upper() callbacks, args = self.routes.match(path) if not callbacks: raise HTTPError(404, "Not found: " + path) if method in callbacks: return callbacks[method], args if method == 'HEAD' and 'GET' in callbacks: return callbacks['GET'], args if 'ANY' in callbacks: return callbacks['ANY'], args allow = [m for m in callbacks if m != 'ANY'] if 'GET' in allow and 'HEAD' not in allow: allow.append('HEAD') raise HTTPError(405, "Method not allowed.", header=[('Allow',",".join(allow))]) def get_url(self, routename, **kargs): scriptname = request.environ.get('SCRIPT_NAME', '').strip('/') + '/' location = self.routes.build(routename, **kargs).lstrip('/') return urljoin(urljoin('/', scriptname), location) def route(self, path=None, method='GET', **kargs): def wrapper(callback): routes = [path] if path else yieldroutes(callback) methods = method.split(';') if isinstance(method, str) else method for r in routes: for m in methods: r, m = r.strip().lstrip('/'), m.strip().upper() old = self.routes.get_route(r, **kargs) if old: old.target[m] = callback else: self.routes.add(r, {m: callback}, **kargs) self.routes.compile() return callback return wrapper def get(self, path=None, method='GET', **kargs): return self.route(path, method, **kargs) def post(self, path=None, method='POST', **kargs): return self.route(path, method, **kargs) def put(self, path=None, method='PUT', **kargs): return self.route(path, method, **kargs) def delete(self, path=None, method='DELETE', **kargs): return self.route(path, method, **kargs) def error(self, code=500): def wrapper(handler): self.error_handler[int(code)] = handler return handler return wrapper def handle(self, url, method): if not self.serve: return HTTPError(503, "Server stopped") try: handler, args = self.match_url(url, method) return handler(**args) except HTTPResponse, e: return e except Exception, e: if isinstance(e, (KeyboardInterrupt, SystemExit, MemoryError))\ or not self.catchall: raise print e return HTTPError(500, 'Unhandled exception', e, format_exc(10))