Ejemplo n.º 1
0
def test_dict2schema_doesnt_add_to_class_registry():
    old_n_entries = len(
        list(
            itertools.chain(
                [classes for _, classes in class_registry._registry.items()])))
    argmap = {"id": fields.Field()}
    dict2schema(argmap)
    dict2schema(argmap)
    new_n_entries = len(
        list(
            itertools.chain(
                [classes for _, classes in class_registry._registry.items()])))
    assert new_n_entries == old_n_entries
Ejemplo n.º 2
0
def test_delimited_list_load_list(web_request, parser):
    web_request.json = {"ids": [1, 2, 3]}
    schema_cls = dict2schema({"ids": fields.DelimitedList(fields.Int())})
    schema = schema_cls()

    parsed = parser.parse(schema, web_request)
    assert parsed["ids"] == [1, 2, 3]
    def use_args(
        self, argmap, locations=None, as_kwargs=False, validate=None, error_status_code=None, error_headers=None
    ):
        """Creates a decorator funtion for socketio on-methods"""
        locations = locations or self.locations
        # Optimization: If argmap is passed as a dictionary, we only need
        # to generate a Schema once
        if isinstance(argmap, Mapping):
            argmap = dict2schema(argmap)()

        def decorator(func):
            def socket_wrapper(data, *args, **kwargs):
                # The first argument is either `self` or `request`
                parsed_args = self.parse(
                    argmap,
                    req=data,
                    locations=locations,
                    validate=validate,
                    error_status_code=error_status_code,
                    error_headers=error_headers,
                )
                if as_kwargs:
                    kwargs.update(parsed_args)
                    return func(*args, **kwargs)
                return func(parsed_args, *args, **kwargs)

            return socket_wrapper

        return decorator
Ejemplo n.º 4
0
def test_delimited_list_custom_delimiter(web_request, parser):
    web_request.json = {"ids": "1|2|3"}
    schema_cls = dict2schema({"ids": fields.DelimitedList(fields.Int(), delimiter="|")})
    schema = schema_cls()

    parsed = parser.parse(schema, web_request)
    assert parsed["ids"] == [1, 2, 3]
Ejemplo n.º 5
0
def test_delimited_list_passed_invalid_type(web_request, parser):
    web_request.json = {"ids": 1}
    schema_cls = dict2schema({"ids": fields.DelimitedList(fields.Int())})
    schema = schema_cls()

    with pytest.raises(ValidationError) as excinfo:
        parser.parse(schema, web_request)
    assert excinfo.value.messages == {"ids": ["Not a valid list."]}
Ejemplo n.º 6
0
def test_delimited_tuple_incorrect_arity(web_request, parser):
    web_request.json = {"ids": "1,2"}
    schema_cls = dict2schema(
        {"ids": fields.DelimitedTuple((fields.Int, fields.Int, fields.Int))})
    schema = schema_cls()

    with pytest.raises(ValidationError):
        parser.parse(schema, web_request)
Ejemplo n.º 7
0
def test_dict2schema_with_nesting():
    argmap = {"nest": fields.Nested({"foo": fields.Field()})}
    schema_cls = dict2schema(argmap)
    assert issubclass(schema_cls, Schema)
    schema = schema_cls()
    assert "nest" in schema.fields
    assert type(schema.fields["nest"]) is fields.Nested
    assert "foo" in schema.fields["nest"].schema.fields
Ejemplo n.º 8
0
    def use_args(self,
                 argmap,
                 req=None,
                 *,
                 location=core.Parser.DEFAULT_LOCATION,
                 as_kwargs=False,
                 validate=None,
                 error_status_code=None,
                 error_headers=None):
        """Decorator that injects parsed arguments into a view callable.
        Supports the *Class-based View* pattern where `request` is saved as an instance
        attribute on a view class.

        :param dict argmap: Either a `marshmallow.Schema`, a `dict`
            of argname -> `marshmallow.fields.Field` pairs, or a callable
            which accepts a request and returns a `marshmallow.Schema`.
        :param req: The request object to parse. Pulled off of the view by default.
        :param str location: Where on the request to load values.
        :param bool as_kwargs: Whether to insert arguments as keyword arguments.
        :param callable validate: Validation function that receives the dictionary
            of parsed arguments. If the function returns ``False``, the parser
            will raise a :exc:`ValidationError`.
        :param int error_status_code: Status code passed to error handler functions when
            a `ValidationError` is raised.
        :param dict error_headers: Headers passed to error handler functions when a
            a `ValidationError` is raised.
        """
        location = location or self.location
        # Optimization: If argmap is passed as a dictionary, we only need
        # to generate a Schema once
        if isinstance(argmap, Mapping):
            argmap = core.dict2schema(argmap, schema_class=self.schema_class)()

        def decorator(func):
            @functools.wraps(func)
            def wrapper(obj, *args, **kwargs):
                # The first argument is either `self` or `request`
                try:  # get self.request
                    request = req or obj.request
                except AttributeError:  # first arg is request
                    request = obj
                # NOTE: At this point, argmap may be a Schema, callable, or dict
                parsed_args = self.parse(
                    argmap,
                    req=request,
                    location=location,
                    validate=validate,
                    error_status_code=error_status_code,
                    error_headers=error_headers,
                )
                args, kwargs = self._update_args_kwargs(
                    args, kwargs, parsed_args, as_kwargs)
                return func(obj, *args, **kwargs)

            wrapper.__wrapped__ = func
            return wrapper

        return decorator
Ejemplo n.º 9
0
 def _get_schema(self, argmap, req):
     if isinstance(argmap, BaseSchema):
         schema = argmap
     elif isinstance(argmap, type) and issubclass(argmap, BaseSchema):
         schema = argmap()
     elif callable(argmap):
         schema = argmap(req)
     else:
         schema = dict2schema(argmap, self.schema_class)()
     return schema
Ejemplo n.º 10
0
def test_delimited_list_default_delimiter(web_request, parser):
    web_request.json = {"ids": "1,2,3"}
    schema_cls = dict2schema({"ids": fields.DelimitedList(fields.Int())})
    schema = schema_cls()

    parsed = parser.parse(schema, web_request)
    assert parsed["ids"] == [1, 2, 3]

    dumped = schema.dump(parsed)
    data = dumped.data if MARSHMALLOW_VERSION_INFO[0] < 3 else dumped
    assert data["ids"] == [1, 2, 3]
Ejemplo n.º 11
0
def test_delimited_list_load_list_errors(web_request, parser):
    web_request.json = {"ids": [1, 2, 3]}
    schema_cls = dict2schema({"ids": fields.DelimitedList(fields.Int())})
    schema = schema_cls()

    with pytest.raises(ValidationError) as excinfo:
        parser.parse(schema, web_request)
    exc = excinfo.value
    assert isinstance(exc, ValidationError)
    errors = exc.args[0]
    assert errors["ids"] == ["Not a valid delimited list."]
Ejemplo n.º 12
0
def test_delimited_tuple_custom_delimiter(web_request, parser):
    web_request.json = {"ids": "1|2"}
    schema_cls = dict2schema({
        "ids":
        fields.DelimitedTuple((fields.Int, fields.Int), delimiter="|")
    })
    schema = schema_cls()

    parsed = parser.parse(schema, web_request)
    assert parsed["ids"] == (1, 2)

    data = schema.dump(parsed)
    assert data["ids"] == "1|2"
Ejemplo n.º 13
0
    def use_args(
        self,
        argmap,
        req=None,
        locations=None,
        as_kwargs=False,
        validate=None,
        error_status_code=None,
        error_headers=None,
    ):
        locations = locations or self.locations
        request_obj = req
        # Optimization: If argmap is passed as a dictionary, we only need
        # to generate a Schema once
        if isinstance(argmap, Mapping):
            argmap = dict2schema(argmap)()

        def decorator(func):
            req_ = request_obj

            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                req_obj = req_

                if not req_obj:
                    req_obj = self.get_request_from_view_args(
                        func, args, kwargs)
                # NOTE: At this point, argmap may be a Schema, or a callable
                parsed_args = self.parse(
                    argmap,
                    req=req_obj,
                    locations=locations,
                    validate=validate,
                    error_status_code=error_status_code,
                    error_headers=error_headers,
                )
                if as_kwargs:
                    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                    # ONLY CHANGE FROM ORIGINAL
                    kwargs.update(animalify(parsed_args, types='snake'))
                    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                    return func(*args, **kwargs)
                else:
                    # Add parsed_args after other positional arguments
                    new_args = args + (parsed_args, )
                    return func(*new_args, **kwargs)

            wrapper.__wrapped__ = func
            return wrapper

        return decorator
Ejemplo n.º 14
0
def annotations2schema(
    func: typing.Callable, type_mapping: typing.Optional[TypeMapping] = None
) -> Schema:
    type_mapping = type_mapping or DEFAULT_TYPE_MAPPING
    annotations = getattr(func, "__annotations__", {})
    signature = inspect.signature(func)
    fields_dict = {}
    for name, annotation in annotations.items():
        # Skip over request argument and return annotation
        if name == "return" or (
            isinstance(annotation, type) and issubclass(annotation, Request)
        ):
            continue

        fields_dict[name] = _type2field(name, annotation, signature, type_mapping)
    return core.dict2schema(fields_dict)
Ejemplo n.º 15
0
def test_delimited_list_as_string_v2(web_request, parser):
    web_request.json = {"dates": "2018-11-01,2018-11-02"}
    schema_cls = dict2schema({
        "dates":
        fields.DelimitedList(fields.DateTime(format="%Y-%m-%d"),
                             as_string=True)
    })
    schema = schema_cls()

    parsed = parser.parse(schema, web_request)
    assert parsed["dates"] == [
        datetime.datetime(2018, 11, 1),
        datetime.datetime(2018, 11, 2),
    ]

    dumped = schema.dump(parsed)
    data = dumped.data if MARSHMALLOW_VERSION_INFO[0] < 3 else dumped
    assert data["dates"] == "2018-11-01,2018-11-02"
Ejemplo n.º 16
0
def test_delimited_tuple_default_delimiter(web_request, parser):
    """
    Test load and dump from DelimitedTuple, including the use of a datetime
    type (similar to a DelimitedList test below) which confirms that we aren't
    relying on __str__, but are properly de/serializing the included fields
    """
    web_request.json = {"ids": "1,2,2020-05-04"}
    schema_cls = dict2schema({
        "ids":
        fields.DelimitedTuple(
            (fields.Int, fields.Int, fields.DateTime(format="%Y-%m-%d")))
    })
    schema = schema_cls()

    parsed = parser.parse(schema, web_request)
    assert parsed["ids"] == (1, 2, datetime.datetime(2020, 5, 4))

    data = schema.dump(parsed)
    assert data["ids"] == "1,2,2020-05-04"
Ejemplo n.º 17
0
def test_delimited_list_with_datetime(web_request, parser):
    """
    Test that DelimitedList(DateTime(format=...)) correctly parses and dumps
    dates to and from strings -- indicates that we're doing proper
    serialization of values in dump() and not just relying on __str__ producing
    correct results
    """
    web_request.json = {"dates": "2018-11-01,2018-11-02"}
    schema_cls = dict2schema(
        {"dates": fields.DelimitedList(fields.DateTime(format="%Y-%m-%d"))})
    schema = schema_cls()

    parsed = parser.parse(schema, web_request)
    assert parsed["dates"] == [
        datetime.datetime(2018, 11, 1),
        datetime.datetime(2018, 11, 2),
    ]

    dumped = schema.dump(parsed)
    data = dumped.data if MARSHMALLOW_VERSION_INFO[0] < 3 else dumped
    assert data["dates"] == "2018-11-01,2018-11-02"
Ejemplo n.º 18
0
def test_dict2schema():
    data_key_kwargs = {
        "load_from" if (MARSHMALLOW_VERSION_INFO[0] < 3) else "data_key":
        "content-type"
    }
    argmap = {
        "id": fields.Int(required=True),
        "title": fields.Str(),
        "description": fields.Str(),
        "content_type": fields.Str(**data_key_kwargs),
    }

    schema_cls = dict2schema(argmap)
    assert issubclass(schema_cls, Schema)

    schema = schema_cls()

    for each in ["id", "title", "description", "content_type"]:
        assert each in schema.fields
    assert schema.fields["id"].required
    if MARSHMALLOW_VERSION_INFO[0] < 3:
        assert schema.opts.strict is True
Ejemplo n.º 19
0
 def __init__(self, nested: typing.Union[typing.Dict, SchemaABC, type, str],
              *args, **kwargs):
     if isinstance(nested, dict):
         nested = dict2schema(nested)
     super().__init__(nested, *args, **kwargs)  # type: ignore
Ejemplo n.º 20
0
 def __init__(self, nested, *args, **kwargs):
     if isinstance(nested, dict):
         nested = dict2schema(nested)
     super(Nested, self).__init__(nested, *args, **kwargs)
Ejemplo n.º 21
0
    def use_args(
        self,
        argmap: ArgMap,
        req: typing.Optional[Request] = None,
        locations: typing.Iterable = None,
        as_kwargs: bool = False,
        validate: Validate = None,
        error_status_code: typing.Optional[int] = None,
        error_headers: typing.Union[typing.Mapping[str, str], None] = None,
    ) -> typing.Callable[..., typing.Callable]:
        """Decorator that injects parsed arguments into a view function or method.

        Receives the same arguments as `webargs.core.Parser.use_args`.
        """
        locations = locations or self.locations
        request_obj = req
        # Optimization: If argmap is passed as a dictionary, we only need
        # to generate a Schema once
        if isinstance(argmap, Mapping):
            argmap = core.dict2schema(argmap)()

        def decorator(func: typing.Callable) -> typing.Callable:
            req_ = request_obj

            if inspect.iscoroutinefunction(func):

                @functools.wraps(func)
                async def wrapper(*args, **kwargs):
                    req_obj = req_

                    if not req_obj:
                        req_obj = self.get_request_from_view_args(
                            func, args, kwargs)
                    # NOTE: At this point, argmap may be a Schema, callable, or dict
                    parsed_args = await self.parse(
                        argmap,
                        req=req_obj,
                        locations=locations,
                        validate=validate,
                        error_status_code=error_status_code,
                        error_headers=error_headers,
                    )
                    if as_kwargs:
                        kwargs.update(parsed_args or {})
                        return await func(*args, **kwargs)
                    else:
                        # Add parsed_args after other positional arguments
                        new_args = args + (parsed_args, )
                        return await func(*new_args, **kwargs)

            else:

                @functools.wraps(func)  # type: ignore
                def wrapper(*args, **kwargs):
                    req_obj = req_

                    if not req_obj:
                        req_obj = self.get_request_from_view_args(
                            func, args, kwargs)
                    # NOTE: At this point, argmap may be a Schema, callable, or dict
                    parsed_args = yield from self.parse(  # type: ignore
                        argmap,
                        req=req_obj,
                        locations=locations,
                        validate=validate,
                        error_status_code=error_status_code,
                        error_headers=error_headers,
                    )
                    if as_kwargs:
                        kwargs.update(parsed_args)
                        return func(*args, **kwargs)  # noqa: B901
                    else:
                        # Add parsed_args after other positional arguments
                        new_args = args + (parsed_args, )
                        return func(*new_args, **kwargs)

            return wrapper

        return decorator
Ejemplo n.º 22
0
def test_load_json_called_by_parse_default(load_json, web_request):
    schema = dict2schema({"foo": fields.Field()})()
    load_json.return_value = {"foo": 1}
    p = Parser()
    p.parse(schema, web_request)
    load_json.assert_called_with(web_request, schema)