Source code for pyrs.resource.base

import inspect

import werkzeug

from . import lib
from . import request
from . import response
from . import errors


[docs]class App(object): """ Resource application, provide routing and execution :param list hooks: List of hook classes (check :py:mod:`.hooks`) :param list resources: Expected items `(path, resource class, [namespace])` :param config: optional configuration values (updated :py:mod:`.conf`) """ hooks = [] #: List of rules, will be **extended** by App(resources=[]) #: Tuple should be presented: ('path', Resource, [namespace]) resources = [] def __init__(self, hooks=None, resources=None, **config): #: Store the configuration (copied from :py:mod:`.conf`) self.config = lib.get_config(getattr(self, 'config', {})) self.functions = {} if hooks is not None: self.hooks = hooks self.config.update(config) self.rules = werkzeug.routing.Map() for resource in self.resources: self.add(*resource) for resource in resources or (): self.add(*resource) self.adapter = self.rules.bind(self['host']) self.setup_hooks() def __getitem__(self, name): return self.config[name]
[docs] def dispatch( self, path_info, method, query=None, body=None, headers=None, cookies=None, session=None ): opts = None req = None try: endpoint, path = self.adapter.match(path_info, method) func = self.functions[endpoint] opts = lib.get_options(func) req = request.Request( opts, self, path, query, body, headers, cookies, session ) kwargs = req.build() except Exception as ex: res = self.handle_client_exceptions( ex, path_info, method, opts, req ) return res.build() try: content = func(**kwargs) res = response.Response(content, self, opts, req) return res.build() except Exception as ex: res = self.handle_exception(ex, opts, req) return res.build()
[docs] def add(self, path, resource, prefix=''): if inspect.isfunction(resource): self._add_function(path, resource, prefix) elif inspect.isclass(resource): self._add_class(path, resource(), prefix) else: self._add_class(path, resource, prefix)
[docs] def handle_client_exceptions( self, ex, path_info, method, opts=None, req=None ): ex = self.transform_exception(ex) res = errors.ErrorResponse(ex, self, opts, req) return res
[docs] def handle_exception(self, ex, opts, req): ex = self.transform_exception(ex) res = errors.ErrorResponse(ex, self, opts, req) return res
[docs] def transform_exception(self, ex): return ex
[docs] def add_rule(self, rule): self.rules.add(rule)
[docs] def set_function(self, name, resource): self.functions[name] = resource
[docs] def setup_hooks(self): pass
[docs] def _add_class(self, path, resource, prefix=''): members = lib.get_resource_members(resource) if not members: raise ValueError( "There is no endpoint in the given resource: %s" % resource ) if not prefix: prefix = getattr(resource, '_name', lib.get_fqname(resource)) for member in members: opts = lib.get_options(member) self._add_function(path+opts['path'], member, prefix)
[docs] def _add_function(self, path, resource, prefix=''): opts = lib.get_options(resource) if opts: if prefix: prefix += '#' name = prefix+opts['name'] rule = self._make_rule(path, opts['methods'], name) self.add_rule(rule) self.set_function(name, resource) else: raise ValueError( "The given function (%s) is not and endpoint endpoint" % resource )
[docs] def _make_rule(self, path, methods, endpoint): return werkzeug.routing.Rule(path, methods=methods, endpoint=endpoint)