Beispiel #1
0
    def test_only_explicitly_declared_fields_are_translated(self, recwarn):
        class UserSchema(Schema):
            _id = fields.Int()

            class Meta:
                title = 'User'
                fields = (
                    '_id',
                    'email',
                )

        res = swagger.schema2jsonschema(UserSchema)
        assert res['type'] == 'object'
        props = res['properties']
        assert '_id' in props
        assert 'email' not in props
        warning = recwarn.pop()
        expected_msg = 'Only explicitly-declared fields will be included in the Schema Object.'
        assert expected_msg in str(warning.message)
        assert issubclass(warning.category, UserWarning)
Beispiel #2
0
    def test_schema(self, spec):
        def pet_view():
            return '...'

        spec.add_path(
            path='/pet',
            view=pet_view,
            operations={'get': {
                'responses': {
                    200: {
                        'schema': PetSchema
                    }
                }
            }})
        p = spec._paths['/pet']
        assert 'get' in p
        op = p['get']
        assert 'responses' in op
        assert op['responses'][200]['schema'] == swagger.schema2jsonschema(
            PetSchema)
    def test_integration_with_docstring_introspection(self, spec):
        class HelloHandler(RequestHandler):
            def get(self):
                """Get a greeting endpoint.
                ---
                description: get a greeting
                responses:
                    200:
                        description: a pet to be returned
                        schema: tests.schemas.PetSchema
                """
                self.write("hello")

        urlspec = (r'/hello', HelloHandler)
        spec.add_path(urlspec=urlspec)
        get_op = spec._paths['/hello']['get']
        assert get_op['description'] == 'get a greeting'
        response = get_op['responses'][200]
        assert response['description'] == 'a pet to be returned'
        assert response['schema'] == swagger.schema2jsonschema(PetSchema)
Beispiel #4
0
    def test_schema2jsonschema_override_name_ma2(self):
        class ExampleSchema(Schema):
            _id = fields.Int(load_from='id', dump_to='id')
            _dt = fields.Int(load_from='lf_no_match', dump_to='dt')
            _lf = fields.Int(load_from='lf')
            _global = fields.Int(load_from='global', dump_to='global')

            class Meta:
                exclude = ('_global', )

        res = swagger.schema2jsonschema(ExampleSchema)
        assert res['type'] == 'object'
        props = res['properties']
        # `_id` renamed to `id`
        assert '_id' not in props and props['id']['type'] == 'integer'
        # `load_from` and `dump_to` do not match, `dump_to` is used
        assert 'lf_no_match' not in props
        assert props['dt']['type'] == 'integer'
        # `load_from` and no `dump_to`, `load_from` is used
        assert props['lf']['type'] == 'integer'
        # `_global` excluded correctly
        assert '_global' not in props and 'global' not in props
Beispiel #5
0
    def test_dump_only_load_only_fields(self, openapi_version):
        spec = APISpec(title='Pets',
                       version='0.1',
                       plugins=['apispec.ext.marshmallow'],
                       openapi_version=openapi_version)

        class UserSchema(Schema):
            _id = fields.Str(dump_only=True)
            name = fields.Str()
            password = fields.Str(load_only=True)

        res = swagger.schema2jsonschema(UserSchema(), spec)
        props = res['properties']
        assert 'name' in props
        # dump_only field appears with readOnly attribute
        assert '_id' in props
        assert 'readOnly' in props['_id']
        # load_only field appears (writeOnly attribute does not exist)
        assert 'password' in props
        if openapi_version == '2.0.0':
            assert 'writeOnly' not in props['password']
        else:
            assert 'writeOnly' in props['password']
Beispiel #6
0
def convert_schemas(d, definitions=None):
    """
    Convert Marshmallow schemas to dict definitions
    """
    if Schema is None:
        raise RuntimeError('Please install marshmallow and apispec')

    if definitions is None:
        definitions = {}
    definitions.update(d.get('definitions', {}))

    new = {'definitions': definitions}
    for k, v in d.items():
        if isinstance(v, dict):
            v = convert_schemas(v, definitions)
        if isinstance(v, (list, tuple)):
            new_v = []
            for item in v:
                if isinstance(item, dict):
                    new_v.append(convert_schemas(item, definitions))
                else:
                    new_v.append(item)
            v = new_v
        if inspect.isclass(v) and issubclass(v, Schema):
            definitions[v.__name__] = schema2jsonschema(v)
            ref = {
                "$ref": "#/definitions/{0}".format(v.__name__)
            }
            if k == 'parameters':
                new[k] = schema2parameters(v)
                new[k][0]['schema'] = ref
            else:
                new[k] = ref
        else:
            new[k] = v

    return new
    def test_schema_array_in_docstring_uses_ref_if_available_v3(self, spec_3):
        def pet_view():
            """Not much to see here.

            ---
            get:
                parameters:
                    - in: body
                      content:
                        application/json:
                            schema:
                                type: array
                                items: tests.schemas.PetSchema
                responses:
                    200:
                        content:
                            application/json:
                                schema:
                                    type: array
                                    items: tests.schemas.PetSchema
            """
            return '...'

        spec_3.add_path(path='/pet', view=pet_view)
        p = spec_3._paths['/pet']
        assert 'get' in p
        op = p['get']
        resolved_schema = {
            'type': 'array',
            'items': swagger.schema2jsonschema(PetSchema),
        }
        request_schema = op['parameters'][0]['content']['application/json'][
            'schema']
        assert request_schema == resolved_schema
        response_schema = op['responses'][200]['content']['application/json'][
            'schema']
        assert response_schema == resolved_schema
Beispiel #8
0
 def test_schema_global_state_untouched_2json(self):
     assert RunSchema._declared_fields['sample']._Nested__schema is None
     data = swagger.schema2jsonschema(RunSchema)
     json.dumps(data)
     assert RunSchema._declared_fields['sample']._Nested__schema is None
Beispiel #9
0
 def test_responses(self, schemas, path):
     response = path['get']['responses']['default']
     assert response['description'] == 'a band'
     assert response['schema'] == swagger.schema2jsonschema(
         schemas.BandSchema)
Beispiel #10
0
def bottle_generate_operations(
    spec,
    bottle_route: bottle.Route,
    description: ControllerDescription,
):
    method_operations = dict()

    # schema based
    if description.input_body:
        schema_class = type(description.input_body.wrapper.processor.schema)
        method_operations.setdefault('parameters', []).append({
            'in': 'body',
            'name': 'body',
            'schema': {
                '$ref': '#/definitions/{}'.format(schema_class.__name__)
            }
        })

    if description.output_body:
        schema_class = type(description.output_body.wrapper.processor.schema)
        method_operations.setdefault('responses', {})\
            [int(description.output_body.wrapper.default_http_code)] = {
                'description': str(description.output_body.wrapper.default_http_code),  # nopep8
                'schema': {
                    '$ref': '#/definitions/{}'.format(schema_class.__name__)
                }
            }

    if description.output_file:
        method_operations.setdefault('produce', []).append(
            description.output_file.wrapper.output_type
        )
        method_operations.setdefault('responses', {})\
            [int(description.output_file.wrapper.default_http_code)] = {
            'description': str(description.output_file.wrapper.default_http_code),  # nopep8
        }

    if description.errors:
        for error in description.errors:
            schema_class = type(error.wrapper.schema)
            method_operations.setdefault('responses', {})\
                [int(error.wrapper.http_code)] = {
                    'description': str(error.wrapper.http_code),
                    'schema': {
                        '$ref': '#/definitions/{}'.format(schema_class.__name__)  # nopep8
                    }
                }

    # jsonschema based
    if description.input_path:
        schema_class = type(description.input_path.wrapper.processor.schema)
        # TODO: look schema2parameters ?
        jsonschema = schema2jsonschema(schema_class, spec=spec)
        for name, schema in jsonschema.get('properties', {}).items():
            method_operations.setdefault('parameters', []).append({
                'in': 'path',
                'name': name,
                'required': name in jsonschema.get('required', []),
                'type': schema['type']
            })

    if description.input_query:
        schema_class = type(description.input_query.wrapper.processor.schema)
        jsonschema = schema2jsonschema(schema_class, spec=spec)
        for name, schema in jsonschema.get('properties', {}).items():
            method_operations.setdefault('parameters', []).append({
                'in': 'query',
                'name': name,
                'required': name in jsonschema.get('required', []),
                'type': schema['type']
            })

    if description.input_files:
        method_operations.setdefault('consume', []).append('multipart/form-data')
        for field_name, field in description.input_files.wrapper.processor.schema.fields.items():
            method_operations.setdefault('parameters', []).append({
                'in': 'formData',
                'name': field_name,
                'required': field.required,
                'type': 'file',
            })

    operations = {
        bottle_route.method.lower(): method_operations,
    }

    return operations
Beispiel #11
0
    def specs_view(self):
        specs = {
            'swagger': '2.0',
            'info': {
                'description': self.__doc__,
                'version': self.version,
                'title': self.name,
            },
            'basePath': self.url_prefix,
            'tags': [],
            'paths': {},
            'definitions': {},
            'host': request.host,
            'schemes': [request.scheme],
        }

        for resource in self.resources:

            if resource.Schema:
                specs['definitions'][resource.meta.name] = schema2jsonschema(resource.Schema)

            specs['tags'].append({
                'name': resource.meta.name,
                'description': resource.__doc__ or resource.__class__.__doc__,
            })
            defaults = {
                'consumes': ['application/json'],
                'produces': ['application/json'],
                'security': [{'api_key': []}],
                'tags': [resource.meta.name],
                'responses': {200: "OK"}
            }

            for endpoint, (url_, name_, params_) in resource.meta.endpoints.values():
                specs['paths'][
                    "%s%s" % (resource.meta.url, url_flask_to_swagger(url_))] = path = {}
                path['get'] = dict(
                    summary=endpoint.__doc__, description=endpoint.__doc__, **defaults)
                if hasattr(endpoint, 'specs'):
                    path['get'].update(endpoint.specs)

            specs['paths'][resource.meta.url] = path = {}
            for method in ('get', 'post'):
                if method.upper() not in resource.methods or not hasattr(resource, 'post'):
                    continue
                view = getattr(resource, method)
                path[method] = dict(summary=view.__doc__, description=view.__doc__, **defaults)

                if method == 'post':
                    path[method]['parameters'] = [{
                        'in': 'body',
                        'name': 'body',
                        'description': 'resource body',
                        'required': True,
                        'schema': {
                            '$ref': '#/definitions/%s' % resource.meta.name
                        }
                    }]

                if resource.meta.specs:
                    path[method].update(resource.meta.specs)

            if resource.meta.url_detail:
                url_detail = url_flask_to_swagger(resource.meta.url_detail)
                path = specs['paths'][url_detail] = {}
                for method in ('get', 'put', 'delete'):
                    if method.upper() not in resource.methods or not hasattr(resource, 'post'):
                        continue
                    view = getattr(resource, method)
                    path[method] = dict(
                        summary=view.__doc__, description=view.__doc__,
                        parameters=[{
                            'name': resource.meta.name,
                            'in': 'path',
                            'description': 'ID of resource',
                            'type': 'string',
                            'required': True
                        }], **defaults)

                    if method == 'put':
                        path[method]['parameters'].append({
                            'in': 'body',
                            'name': 'body',
                            'description': 'resource body',
                            'required': True,
                            'schema': {
                                '$ref': '#/definitions/%s' % resource.meta.name
                            }
                        })

                if resource.meta.specs:
                    path[method].update(resource.meta.specs)

        if isinstance(self.specs, dict):
            specs.update(self.specs)

        response = jsonify(specs)
        response.headers.add_header('Access-Control-Allow-Headers', 'Content-Type, Authorization')
        response.headers.add_header('Access-Control-Allow-Origin', '*')
        response.headers.add_header('Access-Control-Allow-Methods', 'GET,POST,DELETE,PUT')

        return response
Beispiel #12
0
    def test_field2property_nested_ref(self, spec):
        category = fields.Nested(CategorySchema)
        assert swagger.field2property(category) == swagger.schema2jsonschema(CategorySchema)

        cat_with_ref = fields.Nested(CategorySchema, ref='Category')
        assert swagger.field2property(cat_with_ref) == {'$ref': 'Category'}
Beispiel #13
0
 def test_no_required_fields(self):
     class BandSchema(Schema):
         drummer = fields.Str()
         bassist = fields.Str()
     res = swagger.schema2jsonschema(BandSchema)
     assert 'required' not in res
Beispiel #14
0
 def test_required_fields(self):
     class BandSchema(Schema):
         drummer = fields.Str(required=True)
         bassist = fields.Str()
     res = swagger.schema2jsonschema(BandSchema)
     assert res['required'] == ['drummer']
Beispiel #15
0
 def test_invalid_schema(self):
     with pytest.raises(ValueError):
         swagger.schema2jsonschema(None)
Beispiel #16
0
 def test_schema2jsonschema_with_nested_fields(self):
     res = swagger.schema2jsonschema(PetSchema, use_refs=False)
     props = res['properties']
     assert props['category']['items'] == swagger.schema2jsonschema(
         CategorySchema)
Beispiel #17
0
 def test_responses(self, schemas, path):
     response = path['get']['responses']['default']
     assert response['description'] == 'a band'
     assert response['schema'] == swagger.schema2jsonschema(schemas.BandSchema)