Пример #1
0
 def test(self, resolver, modifiers, expected_result_from_name,
          expected_result_from_schema):
     schema = SimpleSchema(only=['id'], exclude=['name'])
     with patch(f'{module_path}.MODIFIERS', new=modifiers):
         with patch(f'{module_path}.resolver',
                    side_effect=resolver) as mock_resolver:
             result_from_name = create_schema_name(
                 name_schema=SimpleSchema.__name__)
             result_from_schema = create_schema_name(schema=schema)
             assert result_from_name == expected_result_from_name
             assert result_from_schema == expected_result_from_schema
Пример #2
0
    def process_query_params_spec(self, schema_ref_name: str):
        if schema_not_in_registry(schema_ref_name):
            # probably schema name was updated from e.g. `UserSchema` to `User` by `_ref_to_spec`
            # try to recover its name if first option was not found
            schema_ref_name = f"{schema_ref_name}Schema"

        new_parameters = []
        name_schema = create_schema_name(name_schema=schema_ref_name)
        if name_schema in self.spec.components.schemas:
            for i_name, i_value in self.spec.components.schemas[name_schema][
                    "properties"].items():
                new_parameter = {
                    "name": i_name,
                    "in": "query",
                    "type": i_value.get("type"),
                    "description": i_value.get("description", ""),
                }
                if "example" in i_value:
                    new_parameter["example"] = i_value["example"]
                if "items" in i_value:
                    new_items = {
                        "type": i_value["items"].get("type"),
                    }
                    if "enum" in i_value["items"]:
                        new_items["enum"] = i_value["items"]["enum"]
                    new_parameter.update({"items": new_items})
                new_parameters.append(new_parameter)
        return new_parameters
Пример #3
0
def resolve_nested_schema(self, schema):
    """Return the Open API representation of a marshmallow Schema.

    Adds the schema to the spec if it isn't already present.

    Typically will return a dictionary with the reference to the schema's
    path in the spec unless the `schema_name_resolver` returns `None`, in
    which case the returned dictoinary will contain a JSON Schema Object
    representation of the schema.

    :param schema: schema to add to the spec
    """
    schema_instance = resolve_schema_instance(schema)
    schema_key = make_schema_key(schema_instance)
    if schema_key not in self.refs:
        schema_cls = self.resolve_schema_class(schema)
        name = self.schema_name_resolver(schema_cls)
        if not name:
            try:
                json_schema = self.schema2jsonschema(schema)
            except RuntimeError:
                raise APISpecError(
                    "Name resolver returned None for schema {schema} which is "
                    "part of a chain of circular referencing schemas. Please"
                    " ensure that the schema_name_resolver passed to"
                    " MarshmallowPlugin returns a string for all circular"
                    " referencing schemas.".format(schema=schema)
                )
            if getattr(schema, "many", False):
                return {"type": "array", "items": json_schema}
            return json_schema
        name = create_schema_name(schema=schema_instance)
        if name not in self.spec.components._schemas:
            self.spec.components.schema(name, schema=schema)
    return self.get_ref_dict(schema_instance)
 def test__ref_to_spec__with_ref_data(self):
     mock_self = Mock()
     mock_self.spec.components._schemas = []
     schema = SomeSchema
     schema_name = create_schema_name(schema)
     data = {'$ref': f'#/definitions/{schema.__name__}'}
     RestfulPlugin._ref_to_spec(mock_self, data)
     mock_self.spec.components.schema.assert_called_once_with(schema_name,
                                                              schema=schema)
     assert data['$ref'] == f'#/definitions/{schema_name}'
Пример #5
0
 def test__ref_to_spec__with_ref_data(self):
     mock_self = Mock()
     mock_self.spec.components.schemas = {}
     schema = SomeSchema
     schema_name = create_schema_name(schema)
     # todo: update later to use spec.get_ref, check for openapi v3
     data = {'$ref': f'#/definitions/{schema.__name__}'}
     RestfulPlugin._ref_to_spec(mock_self, data)
     mock_self.spec.components.schema.assert_called_once_with(schema_name, schema=schema)
     assert data['$ref'] == f'#/definitions/{schema_name}'
Пример #6
0
 def __get_list_resource_fields_filters(self, resource) -> Generator[dict, None, None]:
     schema_name = create_schema_name(schema=resource.schema)
     for i_field_name, i_field in resource.schema._declared_fields.items():
         i_field_spec = self.spec.components._schemas[schema_name]["properties"][i_field_name]
         if not isinstance(i_field, fields.Nested):
             if i_field_spec.get("type") == "object":
                 # Skip filtering by dicts
                 continue
             yield self.__get_parameter_for_not_nested(i_field_name, i_field_spec)
         elif getattr(i_field.schema.Meta, "filtering", False):
             yield from self.__get_parameters_for_nested_with_filtering(i_field, i_field_name)
Пример #7
0
def test_resolve_nested_schema__schema_name_in_spec():
    schema = SomeSchema()
    name = create_schema_name(schema)
    mock_self = Mock()
    mock_self.refs = []
    mock_self.spec.components._schemas = [name]

    result = resolve_nested_schema(mock_self, schema)

    assert result is mock_self.get_ref_dict.return_value
    mock_self.get_ref_dict.assert_called_once_with(schema)
    mock_self.spec.components.schema.assert_not_called()
Пример #8
0
 def _add_definitions_in_spec(self, schema) -> None:
     """
     Add schema in spec
     :param schema: schema marshmallow
     :return:
     """
     name_schema = create_schema_name(schema)
     if name_schema not in self.spec_schemas and name_schema not in self.spec.components._schemas:
         self.spec_schemas[name_schema] = schema
         if APISPEC_VERSION_MAJOR < 1:
             self.spec.definition(name_schema, schema=schema)
         else:
             self.spec.components.schema(name_schema, schema=schema)
Пример #9
0
def test_resolve_nested_schema():
    mock_self = Mock()
    mock_self.refs = []
    mock_self.spec.components.schemas = {}

    schema = SomeSchema()

    result = resolve_nested_schema(mock_self, schema)

    assert result is mock_self.get_ref_dict.return_value
    mock_self.get_ref_dict.assert_called_once_with(schema)
    mock_self.spec.components.schema.assert_called_once_with(
        create_schema_name(schema), schema=schema)
Пример #10
0
 def __get_parameters_for_nested_with_filtering(self, field, field_name) -> Generator[dict, None, None]:
     # Allow JSONB filtering
     field_schema_name = create_schema_name(schema=field.schema)
     component_schema = self.spec.components._schemas[field_schema_name]
     for i_field_jsonb_name, i_field_jsonb in field.schema._declared_fields.items():
         i_field_jsonb_spec = component_schema["properties"][i_field_jsonb_name]
         if i_field_jsonb_spec.get("type") == "object":
             # Пропускаем создание фильтров для dict. Просто не понятно как фильтровать по таким
             # полям
             continue
         new_parameter = self.__get_parameter_for_nested_with_filtering(
             field_name, i_field_jsonb_name, i_field_jsonb_spec,
         )
         yield new_parameter
Пример #11
0
 def __get_parameters_for_declared_fields(self, resource, description) -> Generator[dict, None, None]:
     type_schemas = {resource.schema.Meta.type_}
     for i_field_name, i_field in resource.schema._declared_fields.items():
         if not (isinstance(i_field, Relationship) and i_field.schema.Meta.type_ not in type_schemas):
             continue
         schema_name = create_schema_name(schema=i_field.schema)
         new_parameter = {
             "name": f"fields[{i_field.schema.Meta.type_}]",
             "in": "query",
             "type": "array",
             "required": False,
             "description": description.format(i_field.schema.Meta.type_),
             "items": {
                 "type": "string",
                 "enum": list(self.spec.components._schemas[schema_name]["properties"].keys()),
             },
         }
         type_schemas.add(i_field.schema.Meta.type_)
         yield new_parameter
Пример #12
0
    def test_after_route(self, mock_add_paths_in_spec, plugin):
        tag = 'SomeName'
        url = '/some_resource/<int:id>/'
        plugin.after_route(SomeResourceDetail,
                           'some_view_name', (url, ),
                           tag=tag)

        schema_name = create_schema_name(SomeResourceDetail.schema)

        assert plugin.spec_schemas[schema_name] == SomeResourceDetail.schema
        assert plugin.spec.components._schemas[schema_name]

        assert plugin.spec_tag[tag]

        mock_add_paths_in_spec.assert_called_once_with(
            plugin,
            path=url,
            resource=SomeResourceDetail,
            default_parameters=None,
            default_schema=None,
            tag_name=tag)
Пример #13
0
 def operation_helper(self, path=None, operations=None, **kwargs):
     """Если для query параметров указали схему marshmallow, то раскрываем её и вытаскиваем параметры первого уровня,
         без Nested"""
     resource = kwargs.get("resource", None)
     for m in getattr(resource, "methods", []):
         m = m.lower()
         f = getattr(resource, m)
         m_ops = load_yaml_from_docstring(f.__doc__)
         if m_ops:
             operations.update({m: m_ops})
         self._ref_to_spec(m_ops)
     for method, val in operations.items():
         for index, parametr in enumerate(
                 val["parameters"] if "parameters" in val else []):
             if "in" in parametr and parametr[
                     "in"] == "query" and "schema" in parametr:
                 name_schema = parametr["schema"]["$ref"].split("/")[-1]
                 new_parameters = []
                 name_schema = create_schema_name(name_schema=name_schema)
                 if name_schema in self.spec.components._schemas:
                     for i_name, i_value in self.spec.components._schemas[
                             name_schema]["properties"].items():
                         new_parameter = {
                             "name": i_name,
                             "in": "query",
                             "type": i_value.get("type"),
                             "description": i_value.get("description", ""),
                         }
                         if "items" in i_value:
                             new_items = {
                                 "type": i_value["items"].get("type"),
                             }
                             if "enum" in i_value["items"]:
                                 new_items["enum"] = i_value["items"][
                                     "enum"]
                             new_parameter.update({"items": new_items})
                         new_parameters.append(new_parameter)
                 del val["parameters"][index]
                 val["parameters"].extend(new_parameters)
Пример #14
0
 def _ref_to_spec(self, data):
     """
     Вытаскиваем из описания
     :param data:
     :return:
     """
     if isinstance(data, list):
         for i_v in data:
             self._ref_to_spec(i_v)
     if isinstance(data, dict):
         for k, v in data.items():
             if isinstance(v, list):
                 for i_v in v:
                     self._ref_to_spec(i_v)
             if isinstance(v, dict):
                 self._ref_to_spec(v)
             elif k == "$ref":
                 name_schema = v.split("/")[-1]
                 schema = class_registry.get_class(name_schema)
                 name_schema = create_schema_name(schema=schema)
                 if name_schema not in self.spec.components._schemas:
                     self.spec.components.schema(name_schema, schema=schema)
                 data[k] = "/".join(v.split("/")[:-1] + [name_schema])
Пример #15
0
 def test_invalid_schema_type(self):
     with pytest.raises(TypeError) as e:
         create_schema_name(schema=int)
     assert e.value.args[0] == INVALID_SCHEMA_TYPE
Пример #16
0
 def test_no_schema_name_in_class_registry(self):
     schema_name = "FakeSchema"
     with pytest.raises(ValueError) as e:
         create_schema_name(name_schema=schema_name)
     assert e.value.args[0] == NO_SCHEMA_FOUND_ERROR.format(
         schema_name=schema_name)
Пример #17
0
    def _add_paths_in_spec(
        self,
        path: str = "",
        resource: Any = None,
        tag_name: str = "",
        default_parameters: List = None,
        default_schema: Schema = None,
        **kwargs,
    ) -> None:
        operations = {}
        methods: Set[str] = {i_method.lower() for i_method in resource.methods}

        attributes = {}
        if resource.schema:
            attributes = self.spec.get_ref("schema",
                                           create_schema_name(resource.schema))
        schema = (default_schema if default_schema else {
            "type": "object",
            "properties": {
                "data": {
                    "type": "object",
                    "properties": {
                        "type": {
                            "type": "string",
                        },
                        "id": {
                            "type": "string",
                        },
                        "attributes": attributes,
                        "relationships": {
                            "type": "object",
                        },
                    },
                    "required": [
                        "type",
                    ],
                },
            },
        })

        if "get" in methods:
            operations["get"] = self._get_operations_for_get(
                resource, tag_name, default_parameters)
        if "post" in methods:
            operations["post"] = self._get_operations_for_post(
                schema, tag_name, default_parameters)
        if "patch" in methods:
            operations["patch"] = self._get_operations_for_patch(
                schema, tag_name, default_parameters)
        if "delete" in methods:
            operations["delete"] = self._get_operations_for_delete(
                tag_name, default_parameters)
        rule = None
        for i_rule in self.app.url_map._rules:
            if i_rule.rule == path:
                rule = i_rule
                break
        if APISPEC_VERSION_MAJOR < 1:
            self.spec.add_path(path=path,
                               operations=operations,
                               rule=rule,
                               resource=resource,
                               **kwargs)
        else:
            self.spec.path(path=path,
                           operations=operations,
                           rule=rule,
                           resource=resource,
                           **kwargs)
Пример #18
0
 def test_no_args(self):
     with pytest.raises(ValueError) as e:
         create_schema_name()
     assert e.value.args[0] == NO_ARGS_ERROR