Пример #1
0
def get_operations(view, operations, autodoc=True):
    if operations is not None:
        return operations

    operations = {}

    # views can be class based
    if view.get("attr"):
        global_meta = load_operations_from_docstring(view["callable"].__doc__)
        if global_meta:
            operations.update(global_meta)
        f_view = getattr(view["callable"], view["attr"])
    # or just function callables
    else:
        f_view = view.get("callable")

    methods = view.get("request_methods")
    view_operations = load_operations_from_docstring(f_view.__doc__)
    if not view_operations:
        view_operations = {}
        if is_string(methods):
            methods = [methods]
        if not methods:
            methods = ALL_METHODS[:]
        operation = load_yaml_from_docstring(f_view.__doc__)
        if operation:
            for method in methods:
                view_operations[method.lower()] = operation
        elif autodoc:
            for method in methods:
                view_operations.setdefault(method.lower(), {"responses": {}})
    operations.update(view_operations)

    return operations
Пример #2
0
def path_from_router(spec, view, operations, **kwargs):
    """Path helper that allows passing a bottle view function."""
    operations = utils.load_operations_from_docstring(view.__doc__)
    app = kwargs.get('app', _default_app)
    route = _route_for_view(app, view)
    bottle_path = bottle_path_to_swagger(route.rule)
    return Path(path=bottle_path, operations=operations)
Пример #3
0
def path_from_view(spec, view, operations, **kwargs):
    """Path helper that allows passing a Flask view function."""
    rule = _rule_for_view(view)
    path = flaskpath2swagger(rule.rule)
    operations = utils.load_operations_from_docstring(view.__doc__)
    path = Path(path=path, operations=operations)
    return path
Пример #4
0
    def update_specs(cls, specs):
        if cls.Schema:
            specs.definition(cls.meta.name, schema=cls.Schema)

        operations = utils.load_operations_from_docstring(cls.__doc__)
        specs.add_path(RE_URL.sub(r'{\1}', cls.meta.url), operations=cls.update_operations_specs(
            operations, ('GET', 'POST'),
        ))

        if cls.meta.url_detail:
            ops = cls.update_operations_specs(
                operations, ('GET', 'PUT', 'PATCH', 'DELETE'), parameters=[{
                    'name': cls.meta.name,
                    'in': 'path',
                    'description': 'Resource Identifier',
                    'type': 'string',
                    'required': True,
                }]
            )
            specs.add_path(RE_URL.sub(r'{\1}', cls.meta.url_detail), operations=ops)

        for endpoint, (url_, name_, params_) in cls.meta.endpoints.values():
            specs.add_path(
                RE_URL.sub(r'{\1}', "%s%s" % (cls.meta.url.rstrip('/'), url_)),
                operations=cls.update_operations_specs(
                    operations, params_.get('methods', ('GET',)), method=getattr(cls, name_, None)
                ))
Пример #5
0
    def update_specs(cls, specs):
        if cls.Schema:
            specs.definition(cls.meta.name, schema=cls.Schema)

        operations = utils.load_operations_from_docstring(cls.__doc__)
        specs.add_path(RE_URL.sub(r'{\1}', cls.meta.url),
                       operations=cls.update_operations_specs(
                           operations,
                           ('GET', 'POST'),
                       ))

        if cls.meta.url_detail:
            ops = cls.update_operations_specs(
                operations, ('GET', 'PUT', 'PATCH', 'DELETE'),
                parameters=[{
                    'name': cls.meta.name,
                    'in': 'path',
                    'description': 'Resource Identifier',
                    'type': 'string',
                    'required': True,
                }])
            specs.add_path(RE_URL.sub(r'{\1}', cls.meta.url_detail),
                           operations=ops)

        for endpoint, (url_, name_, params_) in cls.meta.endpoints.values():
            specs.add_path(RE_URL.sub(
                r'{\1}', "%s%s" % (cls.meta.url.rstrip('/'), url_)),
                           operations=cls.update_operations_specs(
                               operations,
                               params_.get('methods', ('GET', )),
                               method=getattr(cls, name_, None)))
Пример #6
0
def path_from_view(spec, view, rule, **kwargs):
    """Path helper that allows passing a Werkzeug view function."""
    path = werkzeugpath2swagger(rule.rule)
    path = urllib.parse.urljoin('/', path.lstrip('/'))
    operations = utils.load_operations_from_docstring(view.__doc__)
    path = Path(path=path, operations=operations)
    return path
Пример #7
0
def path_from_view(spec, app, view, **kwargs):
    """Path helper that allows passing a Chalice view function."""
    kwarg_ops = kwargs.get('operations')
    kwarg_ops = set() if not kwarg_ops else set(kwarg_ops)

    uri, methods = _route_for_view(app,
                                   view,
                                   path=kwargs.get('path', Path()),
                                   operations=kwarg_ops)
    operations = load_operations_from_docstring(view.__doc__)
    if not operations:
        operations = {}

    # check that the operations in the docstring match those of the actual route decorator
    path = Path(path=uri,
                operations={
                    method: op
                    for method, op in iteritems(operations)
                    if method in methods
                })

    # add methods from route decorator that were not in docstring
    for op in methods:
        path.operations.setdefault(op, {})

    return path
Пример #8
0
def path_from_view(spec, view, **kwargs):
    """Path helper that allows passing a Flask view function."""
    rule = _rule_for_view(view)
    path = flaskpath2swagger(rule.rule)
    app_root = current_app.config['APPLICATION_ROOT'] or '/'
    path = urljoin(app_root.rstrip('/') + '/', path.lstrip('/'))
    operations = utils.load_operations_from_docstring(view.__doc__)
    path = Path(path=path, operations=operations)
    return path
Пример #9
0
 def path_helper(self, operations, view, **kwargs):
     """Path helper that allows passing a Sanic view function."""
     operations_from_docs = load_operations_from_docstring(view.__doc__)
     # Operation is specified in OpenAPI specifications
     # Refer: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#operation-object
     if operations_from_docs:
         operations.update(operations_from_docs)
     for method in view.view_class.methods:
         method_name = method.lower()
         method = getattr(view.view_class, method_name)
         method_operation = load_yaml_from_docstring(method.__doc__)
         if method_operation:
             operations[method_name] = load_yaml_from_docstring(
                 method.__doc__)
Пример #10
0
def schema_path_helper(spec, view, **kwargs):
    """Path helper that allows passing a Schema as a response. Responses can be
    defined in a view's docstring.
    """
    operations = (load_operations_from_docstring(view.__doc__)
                  or kwargs.get('operations'))
    if not operations:
        return
    operations = operations.copy()
    for operation in operations.values():
        for response in operation.get('responses', {}).values():
            if 'schema' in response:
                response['schema'] = resolve_schema_dict(
                    spec, response['schema'])
    return Path(operations=operations)
Пример #11
0
def path_from_view(spec, view, **kwargs):
    """Path helper that allows passing a Flask view function."""
    rule = _rule_for_view(view)
    path = flaskpath2swagger(rule.rule)
    app_root = current_app.config['APPLICATION_ROOT'] or '/'
    path = urljoin(app_root.rstrip('/') + '/', path.lstrip('/'))
    operations = utils.load_operations_from_docstring(view.__doc__)
    path = Path(path=path, operations=operations)
    if hasattr(view, 'view_class') and issubclass(view.view_class, MethodView):
        operations = {}
        for method in view.methods:
            method_name = method.lower()
            method = getattr(view.view_class, method_name)
            docstring_yaml = utils.load_yaml_from_docstring(method.__doc__)
            operations[method_name] = docstring_yaml or dict()
        path.operations.update(operations)
    return path
Пример #12
0
 def path_helper(self, operations, view, **kwargs):
     """Path helper that allows passing a Flask view function."""
     rule = self._rule_for_view(view)
     operations.update(
         utils.load_operations_from_docstring(view.__doc__) or {})
     if hasattr(view, 'view_class') and issubclass(view.view_class,
                                                   MethodView):
         for method in view.methods:
             if method in rule.methods:
                 method_name = method.lower()
                 method = getattr(view.view_class, method_name)
                 docstring_yaml = utils.load_yaml_from_docstring(
                     method.__doc__)
                 operations[method_name] = docstring_yaml or dict()
     path = self.flaskpath2openapi(rule.rule)
     app_root = current_app.config['APPLICATION_ROOT'] or '/'
     return urljoin(app_root.rstrip('/') + '/', path.lstrip('/'))
Пример #13
0
    def path_helper(self, operations, resource, **kwargs):
        """Path helper that allows passing a Falcon resource instance."""
        resource_uri_mapping = self._generate_resource_uri_mapping(self._app)

        if resource not in resource_uri_mapping:
            raise APISpecError("Could not find endpoint for resource {0}".format(resource))

        operations.update(utils.load_operations_from_docstring(resource.__doc__) or {})
        path = resource_uri_mapping[resource]

        for method in falcon.constants.HTTP_METHODS:
            http_verb = method.lower()
            method_name = "on_" + http_verb
            if hasattr(resource, method_name):
                method = getattr(resource, method_name)
                docstring_yaml = utils.load_yaml_from_docstring(method.__doc__)
                operations[http_verb] = docstring_yaml or dict()

        return path
Пример #14
0
def schema_path_helper(spec, view=None, **kwargs):
    """Path helper that allows passing a Schema as a response. Responses can be
    defined in a view's docstring.
    ::

        from pprint import pprint

        from my_app import Users, UserSchema

        class UserHandler:
            def get(self, user_id):
                '''Get a user endpoint.
                ---
                description: Get a user
                responses:
                    200:
                        description: A user
                        schema: UserSchema
                '''
                user = Users.get(id=user_id)
                schema = UserSchema()
                return schema.dumps(user)

        urlspec = (r'/users/{user_id}', UserHandler)
        spec.add_path(urlspec=urlspec)
        pprint(spec.to_dict()['paths'])
        # {'/users/{user_id}': {'get': {'description': 'Get a user',
        #                               'responses': {200: {'description': 'A user',
        #                                                   'schema': {'$ref': '#/definitions/User'}}}}}}

    ::

        from pprint import pprint

        from my_app import Users, UserSchema

        class UsersHandler:
            def get(self):
                '''Get users endpoint.
                ---
                description: Get a list of users
                responses:
                    200:
                        description: A list of user
                        schema:
                            type: array
                            items: UserSchema
                '''
                users = Users.all()
                schema = UserSchema(many=True)
                return schema.dumps(users)

        urlspec = (r'/users', UsersHandler)
        spec.add_path(urlspec=urlspec)
        pprint(spec.to_dict()['paths'])
        # {'/users': {'get': {'description': 'Get a list of users',
        #                     'responses': {200: {'description': 'A list of users',
        #                                         'schema': {'type': 'array',
        #                                                    'items': {'$ref': '#/definitions/User'}}}}}}}

    """
    operations = (
        kwargs.get('operations') or
        (view and load_operations_from_docstring(view.__doc__))
    )
    if not operations:
        return None
    operations = operations.copy()
    return Path(operations=operations)
Пример #15
0
def resource_path_helper(spec, path, resource):
    """Provides path when given a FlaskRestful resource"""
    operations = utils.load_operations_from_docstring(resource.__doc__)
    return Path(path=path, operations=operations)
Пример #16
0
def docstring_path_helper(spec, path, router, func, **kwargs):
    operations = load_operations_from_docstring(func.__doc__)

    cp_config = func._cp_config

    if operations is not None:
        for method, data in operations.items():

            if cp_config.get('tools.authentication.on', True):
                data['security'] = [{'Bearer': []}]

            if 'tools.model_in.cls' in cp_config:
                model_cls = cp_config['tools.model_in.cls']
                spec.definition(model_cls.__name__,
                                **parse_model(spec, model_cls))

                data['requestBody']['required'] = True
                data['requestBody']['content'] = {
                    'application/json': {
                        'schema': {
                            '$ref':
                            '#/components/schemas/' + model_cls.__name__
                        }
                    }
                }

            if 'tools.model_params.cls' in cp_config:
                model_cls = cp_config['tools.model_params.cls']
                data['parameters'] = data.get('parameters', [])

                # In query vs in path
                for key, obj in model_cls.__dict__.items():
                    inn = 'query'
                    if '{' + key + '}' in path.path:
                        inn = 'path'
                    if isinstance(obj, FieldDescriptor):
                        data['parameters'].append({
                            'name':
                            key,
                            'in':
                            inn,
                            'required':
                            model_cls._fields[key].required,
                            'schema':
                            parse_model_type(spec, model_cls._fields[key])
                        })

            if 'tools.model_out.cls' in cp_config:
                model_cls = cp_config['tools.model_out.cls']
                spec.definition(model_cls.__name__,
                                **parse_model(spec, model_cls))
                data['responses'][200]['content'] = {
                    'application/json': {
                        'schema': {
                            '$ref':
                            '#/components/schemas/' + model_cls.__name__
                        }
                    }
                }

            if 'tools.model_out_pagination.cls' in cp_config:
                model_cls = cp_config['tools.model_out_pagination.cls']
                spec.definition(model_cls.__name__,
                                **parse_model(spec, model_cls))
                data['responses'][200]['content'] = {
                    'application/json': {
                        'schema': {
                            'type': 'array',
                            'items': {
                                '$ref':
                                '#/components/schemas/' + model_cls.__name__
                            }
                        }
                    }
                }

            if isinstance(router, SandwichProjectRouter):
                data['parameters'] = data.get('parameters', [])
                data['parameters'].append({
                    'name': 'project_name',
                    'in': 'path',
                    'required': True,
                    'schema': {
                        'type': 'string'
                    }
                })

            if 'tools.enforce_permission.permission_name' in cp_config:
                data['x-required-permission'] = cp_config[
                    'tools.enforce_permission.permission_name']

    return Path(path=path.path, operations=operations)
Пример #17
0
from apispec import APISpec, utils
from apispec.ext.flask import flaskpath2swagger

from simple_flask_project.app import app
from simple_flask_project.schemas import GLOBAL_SCHEMA_MAP

spec = APISpec(title='Users API',
               version='1.0.0',
               plugins=('apispec.ext.flask', ),
               openapi_version='3.0.0',
               security=[],
               components={})

for r in app.url_map.iter_rules():
    view = app.view_functions.get(r.endpoint)
    operations = utils.load_operations_from_docstring(view.__doc__)
    path = flaskpath2swagger(r.rule)

    if not operations:
        continue

    for verb in operations:
        resp = operations.get(verb).get('responses')
        for status in resp:
            val = resp.get(status)
            content = resp.get(status).get('schema')
            if content:
                # Check if mapping is present in global schema map
                if GLOBAL_SCHEMA_MAP.get(content):
                    val.update({
                        'content': {
Пример #18
0
def add_pyramid_paths(spec,
                      route_name,
                      request=None,
                      request_method=None,
                      operations=None,
                      **kwargs):
    """

    Adds a route and view info to spec

    :param spec:
        ApiSpec object
    :param route_name:
        Route name to inspect
    :param request:
        Request object, if `None` then `get_current_request()` will be used
    :param request_method:
        Request method predicate
    :param operations:
        Operations dict that will be used instead of introspection
    :param kwargs:
        Additional kwargs for predicate matching
    :return:

    """
    from pyramid.threadlocal import get_current_request

    if request is None:
        request = get_current_request()

    registry = request.registry
    introspector = registry.introspector
    route = introspector.get("routes", route_name)
    views = introspector.related(route)

    # needs to be rewritten to internal name
    if request_method:
        kwargs["request_methods"] = request_method
        # kwargs.setdefault('route_name', route_name)

    for view in views:
        matches = True
        for kw in kwargs.keys():
            # request_methods can be either a list of strings or a string
            # so lets normalize via sets
            if kw == "request_methods":
                if is_string(kwargs[kw]):
                    kwargs[kw] = [kwargs[kw]]
                methods = view.get(kw) or ALL_METHODS
                if is_string(methods):
                    methods = [methods]
                if not set(kwargs[kw] or []).intersection(methods):
                    matches = False
            else:
                if not view.get(kw) == kwargs[kw]:
                    matches = False

        if not matches:
            continue

        final_operations = {}

        # views can be class based
        if view.get("attr"):
            global_meta = load_operations_from_docstring(
                view["callable"].__doc__)
            if global_meta:
                final_operations.update(global_meta)
            f_view = getattr(view["callable"], view["attr"])
        # or just function callables
        else:
            f_view = view.get("callable")

        if operations is None:
            methods = view.get("request_methods")
            view_operations = load_operations_from_docstring(f_view.__doc__)
            if not view_operations:
                view_operations = {}
                if is_string(methods):
                    methods = [methods]
                if not methods:
                    methods = ALL_METHODS[:]
                operation = load_yaml_from_docstring(f_view.__doc__)
                if operation:
                    for method in methods:
                        view_operations[method.lower()] = operation
            final_operations.update(view_operations)
        else:
            final_operations = operations
        spec.add_path(route["pattern"], operations=final_operations)
Пример #19
0
 def path_helper(self, operations, view, **kwargs):
     """Path helper that allows passing a bottle view function."""
     operations.update(utils.load_operations_from_docstring(view.__doc__) or {})
     app = kwargs.get('app', _default_app)
     route = self._route_for_view(app, view)
     return self.bottle_path_to_openapi(route.rule)