def wrapper(request): # if the args contain a klass argument then use it to resolve the view # location (if the view argument isn't a callable) ob = None view_ = view if 'klass' in args and not callable(view): # XXX: given that request.context exists and root-factory # only expects request param, having params seems unnecessary # ob = args['klass'](request) params = dict(request=request) if 'factory' in route_args: params['context'] = request.context ob = args['klass'](**params) if is_string(view): view_ = getattr(ob, view.lower()) elif isinstance(view, _UnboundView): view_ = view.make_bound_view(ob) # the validators can either be a list of callables or contain some # non-callable values. In which case we want to resolve them using the # object if any validators = args.get('validators', ()) for validator in validators: if is_string(validator) and ob is not None: validator = getattr(ob, validator) validator(request, **args) # only call the view if we don't have validation errors if len(request.errors) == 0: try: # If we have an object, it already has the request. if ob: response = view_() else: response = view_(request) except Exception: # cors headers need to be set if an exception was raised request.info['cors_checked'] = False raise # check for errors and return them if any if len(request.errors) > 0: # We already checked for CORS, but since the response is created # again, we want to do that again before returning the response. request.info['cors_checked'] = False return args['error_handler'](request) # if the view returns its own response, cors headers need to be set if isinstance(response, Response): request.info['cors_checked'] = False # We can't apply filters at this level, since "response" may not have # been rendered into a proper Response object yet. Instead, give the # request a reference to its api_kwargs so that a tween can apply them. # We also pass the object we created (if any) so we can use it to find # the filters that are in fact methods. request.cornice_args = (args, ob) return response
def wrapper(request): # if the args contain a klass argument then use it to resolve the view # location (if the view argument isn't a callable) ob = None view_ = view if 'klass' in args and not callable(view): params = dict(request=request) if 'factory' in args and 'acl' not in args: params['context'] = request.context ob = args['klass'](**params) if is_string(view): view_ = getattr(ob, view.lower()) elif isinstance(view, _UnboundView): view_ = view.make_bound_view(ob) # set data deserializer if 'deserializer' in args: request.deserializer = args['deserializer'] # do schema validation if 'schema' in args: validate_colander_schema(args['schema'], request) elif hasattr(ob, 'schema'): validate_colander_schema(ob.schema, request) # the validators can either be a list of callables or contain some # non-callable values. In which case we want to resolve them using the # object if any validators = args.get('validators', ()) for validator in validators: if is_string(validator) and ob is not None: validator = getattr(ob, validator) validator(request) # only call the view if we don't have validation errors if len(request.errors) == 0: # if we have an object, the request had already been passed to it if ob: response = view_() else: response = view_(request) # check for errors and return them if any if len(request.errors) > 0: # We already checked for CORS, but since the response is created # again, we want to do that again before returning the response. request.info['cors_checked'] = False return args['error_handler'](request.errors) # We can't apply filters at this level, since "response" may not have # been rendered into a proper Response object yet. Instead, give the # request a reference to its api_kwargs so that a tween can apply them. # We also pass the object we created (if any) so we can use it to find # the filters that are in fact methods. request.cornice_args = (args, ob) return response
def wrapper(request): # if the args contain a klass argument then use it to resolve the view # location (if the view argument isn't a callable) ob = None view_ = view if 'klass' in args and not callable(view): params = dict(request=request) if 'factory' in args and 'acl' not in args: params['context'] = args['factory'](request) ob = args['klass'](**params) if is_string(view): view_ = getattr(ob, view.lower()) # set data deserializer if 'deserializer' in args: request.deserializer = args['deserializer'] # do schema validation if 'schema' in args: validate_colander_schema(args['schema'], request) elif hasattr(ob, 'schema'): validate_colander_schema(ob.schema, request) # the validators can either be a list of callables or contain some # non-callable values. In which case we want to resolve them using the # object if any validators = args.get('validators', ()) for validator in validators: if is_string(validator) and ob is not None: validator = getattr(ob, validator) validator(request) # only call the view if we don't have validation errors if len(request.errors) == 0: # if we have an object, the request had already been passed to it if ob: response = view_() else: response = view_(request) # check for errors and return them if any if len(request.errors) > 0: # We already checked for CORS, but since the response is created # again, we want to do that again before returning the response. request.info['cors_checked'] = False return args['error_handler'](request.errors) # We can't apply filters at this level, since "response" may not have # been rendered into a proper Response object yet. Instead, give the # request a reference to its api_kwargs so that a tween can apply them. # We also pass the object we created (if any) so we can use it to find # the filters that are in fact methods. request.cornice_args = (args, ob) return response
def _resolve_obj_to_docstring(self, obj, args): # Resolve a view or validator to an object if type string # and return docstring. if is_string(obj): if 'klass' in args: ob = args['klass'] obj_ = getattr(ob, obj.lower()) return format_docstring(obj_) else: return '' else: return format_docstring(obj)
def apply_filters(request, response): if request.matched_route is not None: # do some sanity checking on the response using filters services = request.registry.get('cornice_services', {}) pattern = request.matched_route.pattern service = services.get(pattern, None) if service is not None: kwargs, ob = getattr(request, "cornice_args", ({}, None)) for _filter in kwargs.get('filters', []): if is_string(_filter) and ob is not None: _filter = getattr(ob, _filter) try: response = _filter(response, request) except TypeError: response = _filter(response) if service.cors_enabled: apply_cors_post_request(service, request, response) return response
def apply_filters(request, response): if request.matched_route is not None: # do some sanity checking on the response using filters services = request.registry.cornice_services pattern = request.matched_route.pattern service = services.get(pattern, None) if service is not None: kwargs, ob = getattr(request, "cornice_args", ({}, None)) for _filter in kwargs.get('filters', []): if is_string(_filter) and ob is not None: _filter = getattr(ob, _filter) try: response = _filter(response, request) except TypeError: response = _filter(response) if service.cors_enabled: apply_cors_post_request(service, request, response) return response
def _render_service(self, service): service_id = "service-%d" % self.env.new_serialno('service') service_node = nodes.section(ids=[service_id]) title = '%s service at %s' % (service.name.title(), service.path) service_node += nodes.title(text=title) if service.description is not None: service_node += rst2node(trim(service.description)) for method, view, args in service.definitions: if method == 'HEAD': #Skip head - this is essentially duplicating the get docs. continue method_id = '%s-%s' % (service_id, method) method_node = nodes.section(ids=[method_id]) method_node += nodes.title(text=method) if is_string(view): if 'klass' in args: ob = args['klass'] view_ = getattr(ob, view.lower()) docstring = trim(view_.__doc__ or "") + '\n' else: docstring = trim(view.__doc__ or "") + '\n' if 'schema' in args: schema = args['schema'] attrs_node = nodes.inline() for location in ('header', 'querystring', 'body'): attributes = schema.get_attributes(location=location) if attributes: attrs_node += nodes.inline(text='values in the %s' % location) location_attrs = nodes.bullet_list() for attr in attributes: temp = nodes.list_item() desc = "%s : " % attr.name # Get attribute data-type if hasattr(attr, 'type'): attr_type = attr.type elif hasattr(attr, 'typ'): attr_type = attr.typ.__class__.__name__ desc += " %s, " % attr_type if attr.required: desc += "required " else: desc += "optional " temp += nodes.inline(text=desc) location_attrs += temp attrs_node += location_attrs method_node += attrs_node for validator in args.get('validators', ()): if validator.__doc__ is not None: docstring += trim(validator.__doc__) if 'accept' in args: accept = to_list(args['accept']) if callable(accept): if accept.__doc__ is not None: docstring += accept.__doc__.strip() else: accept_node = nodes.strong(text='Accepted content types:') node_accept_list = nodes.bullet_list() accept_node += node_accept_list for item in accept: temp = nodes.list_item() temp += nodes.inline(text=item) node_accept_list += temp method_node += accept_node node = rst2node(docstring) DocFieldTransformer(self).transform_all(node) if node is not None: method_node += node renderer = args['renderer'] if renderer == 'simplejson': renderer = 'json' response = nodes.paragraph() response += nodes.strong(text='Response: %s' % renderer) method_node += response service_node += method_node return service_node
def decorate_view(view, args, method): """Decorate a given view with cornice niceties. This function returns a function with the same signature than the one you give as :param view: :param view: the view to decorate :param args: the args to use for the decoration :param method: the HTTP method """ def wrapper(request): # if the args contain a klass argument then use it to resolve the view # location (if the view argument isn't a callable) ob = None view_ = view if 'klass' in args and not callable(view): params = dict(request=request) if 'factory' in args and 'acl' not in args: params['context'] = request.context ob = args['klass'](**params) if is_string(view): view_ = getattr(ob, view.lower()) elif isinstance(view, _UnboundView): view_ = view.make_bound_view(ob) # set data deserializer if 'deserializer' in args: request.deserializer = args['deserializer'] # do schema validation if 'schema' in args: validate_colander_schema(args['schema'], request) elif hasattr(ob, 'schema'): validate_colander_schema(ob.schema, request) # the validators can either be a list of callables or contain some # non-callable values. In which case we want to resolve them using the # object if any validators = args.get('validators', ()) for validator in validators: if is_string(validator) and ob is not None: validator = getattr(ob, validator) validator(request) # only call the view if we don't have validation errors if len(request.errors) == 0: try: # If we have an object, it already has the request. if ob: response = view_() else: response = view_(request) except: # cors headers need to be set if an exception was raised request.info['cors_checked'] = False raise # check for errors and return them if any if len(request.errors) > 0: # We already checked for CORS, but since the response is created # again, we want to do that again before returning the response. request.info['cors_checked'] = False return args['error_handler'](request.errors) # if the view returns its own response, cors headers need to be set if isinstance(response, Response): request.info['cors_checked'] = False # We can't apply filters at this level, since "response" may not have # been rendered into a proper Response object yet. Instead, give the # request a reference to its api_kwargs so that a tween can apply them. # We also pass the object we created (if any) so we can use it to find # the filters that are in fact methods. request.cornice_args = (args, ob) return response # return the wrapper, not the function, keep the same signature if not is_string(view): functools.update_wrapper(wrapper, view) # Set the wrapper name to something useful wrapper.__name__ = "{0}__{1}".format(func_name(view), method) return wrapper
def _render_service(self, service): service_id = "service-%d" % self.env.new_serialno('service') service_node = nodes.section(ids=[service_id]) title = '%s service at %s' % (service.name.title(), service.path) service_node += nodes.title(text=title) if service.description is not None: service_node += rst2node(trim(service.description)) for method, view, args in service.definitions: if method == 'HEAD': #Skip head - this is essentially duplicating the get docs. continue method_id = '%s-%s' % (service_id, method) method_node = nodes.section(ids=[method_id]) method_node += nodes.title(text=method) if is_string(view): if 'klass' in args: ob = args['klass'] view_ = getattr(ob, view.lower()) docstring = trim(view_.__doc__ or "") + '\n' else: docstring = trim(view.__doc__ or "") + '\n' if 'schema' in args: schema = args['schema'] attrs_node = nodes.inline() for location in ('header', 'querystring', 'body'): attributes = schema.get_attributes(location=location) if attributes: attrs_node += nodes.inline( text='values in the %s' % location) location_attrs = nodes.bullet_list() for attr in attributes: temp = nodes.list_item() desc = "%s : " % attr.name # Get attribute data-type if hasattr(attr, 'type'): attr_type = attr.type elif hasattr(attr, 'typ'): attr_type = attr.typ.__class__.__name__ desc += " %s, " % attr_type if attr.required: desc += "required " else: desc += "optional " temp += nodes.inline(text=desc) location_attrs += temp attrs_node += location_attrs method_node += attrs_node for validator in args.get('validators', ()): if validator.__doc__ is not None: docstring += trim(validator.__doc__) if 'accept' in args: accept = to_list(args['accept']) if callable(accept): if accept.__doc__ is not None: docstring += accept.__doc__.strip() else: accept_node = nodes.strong(text='Accepted content types:') node_accept_list = nodes.bullet_list() accept_node += node_accept_list for item in accept: temp = nodes.list_item() temp += nodes.inline(text=item) node_accept_list += temp method_node += accept_node node = rst2node(docstring) DocFieldTransformer(self).transform_all(node) if node is not None: method_node += node renderer = args['renderer'] if renderer == 'simplejson': renderer = 'json' response = nodes.paragraph() response += nodes.strong(text='Response: %s' % renderer) method_node += response service_node += method_node return service_node
def _render_service(self, service): service_id = "service-%d" % self.env.new_serialno('service') service_node = nodes.section(ids=[service_id]) title = '%s service at %s' % (service.name.title(), service.path) title = title.replace('Collection_', '') service_node += nodes.title(text=title) if service.description is not None: service_node += rst2node(trim(service.description)) for method, view, args in service.definitions: if method == 'HEAD': # Skip head - this is essentially duplicating the get docs. continue if method in self.options.get('ignore-methods', []): continue method_id = '%s-%s' % (service_id, method) method_node = nodes.section(ids=[method_id]) method_node += nodes.title(text=method) if is_string(view): if 'klass' in args: ob = args['klass'] view_ = getattr(ob, view.lower()) docstring = trim(view_.__doc__ or "") + '\n' else: docstring = trim(view.__doc__ or "") + '\n' print('Replacing BIMT strings with app strings in API docstrings.') docstring = docstring.replace( 'BIMT', self.options.get('app-title', 'BIMT')) docstring = docstring.replace( 'http://localhost:8080', self.options.get('app-url', 'http://localhost:8080')) # noqa attrs_node = None if 'schema' in args: schema = args['schema'] attrs_node = nodes.inline() for location in ('header', 'querystring', 'body'): attributes = schema.get_attributes(location=location) if attributes: attrs_node += nodes.inline( text='Values in the %s:' % location) location_attrs = nodes.bullet_list() for attr in attributes: temp = nodes.list_item() # check for permissions column_name = attr.name if column_name == 'version': column_name = 'v' elif column_name == 'created': column_name = 'c' elif column_name == 'modified': column_name = 'm' # find attr in SQLAlchemy table definition and # check that it has view permission if not getattr(args['klass'], 'model', None): continue columns = args['klass'].model.__table__.columns if column_name in columns.keys(): info = getattr(columns[column_name], 'info', None) permission = info.get('colanderalchemy', {}).get('view_permission') if permission != BimtPermissions.view: continue else: continue # Get attribute data-type if hasattr(attr, 'type'): attr_type = attr.type elif hasattr(attr, 'typ'): attr_type = attr.typ.__class__.__name__ else: attr_type = None temp += nodes.strong(text=attr.name) if attr_type is not None: temp += nodes.inline(text=' (%s)' % attr_type) if not attr.required or attr.description: temp += nodes.inline(text=' - ') if not attr.required: if attr.missing is not None and \ not isinstance(attr.missing, colander._drop): default = json.dumps(attr.missing) temp += nodes.inline( text='(default: %s) ' % default) else: temp += nodes.inline( text='(optional) ') if attr.description: temp += nodes.inline(text=attr.description) location_attrs += temp attrs_node += location_attrs for validator in args.get('validators', ()): if validator.__doc__ is not None: docstring += trim(validator.__doc__) accept_node = False if 'accept' in args: accept = to_list(args['accept']) if callable(accept): if accept.__doc__ is not None: docstring += accept.__doc__.strip() elif len(accept) == 1: accept_node = nodes.strong( text='Accepted content type: {}'.format(accept[0])) else: accept_node = nodes.strong(text='Accepted content types:') node_accept_list = nodes.bullet_list() accept_node += node_accept_list for item in accept: temp = nodes.list_item() temp += nodes.inline(text=item) node_accept_list += temp node = rst2node(docstring) DocFieldTransformer(self).transform_all(node) if node is not None: method_node += node if attrs_node: method_node += attrs_node if accept_node: method_node += accept_node renderer = args['renderer'] if renderer == 'simplejson': renderer = 'json' response = nodes.paragraph() response += nodes.strong(text='Response: %s' % renderer) method_node += response service_node += method_node return service_node