def test_argmap2schema_doesnt_add_to_class_registry(): old_n_entries = len( list(itertools.chain([classes for _, classes in class_registry._registry.items()])) ) argmap = {'id': fields.Field()} argmap2schema(argmap) argmap2schema(argmap) new_n_entries = len( list(itertools.chain([classes for _, classes in class_registry._registry.items()])) ) assert new_n_entries == old_n_entries
class ServerInfoApi(Resource): @doc(description="Return FreeDiscovery server information " " (versions, etc).") @marshal_with( argmap2schema({ 'version': wfields.Nested({'number': wfields.Str()}), 'env': wfields.Nested({'python_version': wfields.Str()}), 'config': wfields.Nested({ 'cache_dir': wfields.Str(), 'debug': wfields.Boolean(), 'hostname': wfields.Str(), 'log_file': wfields.Str(), 'n_workers': wfields.Int(), 'port': wfields.Int(), 'server': wfields.Str() }) })) def get(self): out = {'version': {}, 'env': {}} out['version']['number'] = __version__ out['env']['python_version'] = sys.version out['config'] = self._fd_config return out
def test_delimited_list_custom_delimiter(web_request, parser): web_request.json = {'ids': '1|2|3'} schema_cls = argmap2schema({'ids': fields.DelimitedList(fields.Int(), delimiter='|')}) schema = schema_cls() parsed = parser.parse(schema, web_request) assert parsed['ids'] == [1, 2, 3]
def test_delimited_list_load_list(web_request, parser): web_request.json = {'ids': [1, 2, 3]} schema_cls = argmap2schema({'ids': fields.DelimitedList(fields.Int())}) schema = schema_cls() parsed = parser.parse(schema, web_request) assert parsed['ids'] == [1, 2, 3]
def test_argmap2schema_with_nesting(): argmap = {"nest": fields.Nested({"foo": fields.Field()})} schema_cls = argmap2schema(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
def test_delimited_list_passed_invalid_type(web_request, parser): web_request.json = {'ids': 1} schema_cls = argmap2schema({'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.']}
def test_delimited_list_custom_delimiter(web_request, parser): web_request.json = {"ids": "1|2|3"} schema_cls = argmap2schema( {"ids": fields.DelimitedList(fields.Int(), delimiter="|")}) schema = schema_cls() parsed = parser.parse(schema, web_request) assert parsed["ids"] == [1, 2, 3]
def test_argmap2schema_with_nesting(): argmap = {'nest': fields.Nested({'foo': fields.Field()})} schema_cls = argmap2schema(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
def test_delimited_list_as_string(web_request, parser): web_request.json = {'ids': '1,2,3'} schema_cls = argmap2schema({'ids': fields.DelimitedList(fields.Int(), as_string=True)}) schema = schema_cls() parsed = parser.parse(schema, web_request) assert parsed['ids'] == [1, 2, 3] dumped = schema.dump(parsed).data assert dumped['ids'] == '1,2,3'
def test_delimited_list_default_delimiter(web_request, parser): web_request.json = {'ids': '1,2,3'} schema_cls = argmap2schema({'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]
def use_args( self, argmap, req=None, locations=core.Parser.DEFAULT_LOCATIONS, as_kwargs=False, validate=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 tuple locations: Where on the request to search for 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`. """ locations = locations or self.locations # Optimization: If argmap is passed as a dictionary, we only need # to generate a Schema once if isinstance(argmap, collections.Mapping): argmap = core.argmap2schema(argmap)() 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, locations=locations, validate=validate, force_all=as_kwargs, ) if as_kwargs: kwargs.update(parsed_args) return func(obj, *args, **kwargs) else: return func(obj, parsed_args, *args, **kwargs) wrapper.__wrapped__ = func return wrapper return decorator
def test_delimited_list_as_string(web_request, parser): web_request.json = {"ids": "1,2,3"} schema_cls = argmap2schema( {"ids": fields.DelimitedList(fields.Int(), as_string=True)}) 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"
def use_args(self, argmap, req=None, locations=None, as_kwargs=False, validate=None): """Decorator that injects parsed arguments into a view function or method. .. warning:: This will not work with `async def` coroutines. Either use a generator-based coroutine decorated with `asyncio.coroutine` or use the `parse <webargs.async.AsyncParser.parse>` 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, collections.Mapping): argmap = core.argmap2schema(argmap)() def decorator(func): req_ = request_obj @functools.wraps(func) def wrapper(*args, **kwargs): req_obj = req_ # if as_kwargs is passed, must include all args force_all = as_kwargs 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(argmap, req=req_obj, locations=locations, validate=validate, force_all=force_all) if as_kwargs: kwargs.update(parsed_args) 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
def use_args(self, argmap, req=None, locations=None, as_kwargs=False, validate=None): locations = locations or self.locations request_obj = req if isinstance(argmap, collections.Mapping): argmap = argmap2schema(argmap)() def decorator(func): req_ = request_obj @functools.wraps(func) def wrapper(*args, **kwargs): req_obj = req_ # if as_kwargs is passed, must include all args force_all = as_kwargs 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 try: parsed_args = self.parse(argmap, req=req_obj, locations=locations, validate=validate, force_all=force_all) except ParamException: return jsonify({'ret': -1, 'msg': 'params error'}), 400 else: if as_kwargs: kwargs.update(parsed_args) 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
def use_args(self, argmap, req=None, locations=None, as_kwargs=False, validate=None): """Decorator that injects parsed arguments into a view function or method. .. warning:: This will not work with `async def` coroutines. Either use a generator-based coroutine decorated with `asyncio.coroutine` or use the `parse <webargs.async.AsyncParser.parse>` method. Receives the same arguments as `webargs.core.Parser.use_args`. """ locations = locations or self.locations if isinstance(argmap, ma.Schema): schema = argmap else: schema = core.argmap2schema(argmap)() request_obj = req def decorator(func): req_ = request_obj @functools.wraps(func) def wrapper(*args, **kwargs): req_obj = req_ # if as_kwargs is passed, must include all args force_all = as_kwargs if not req_obj: req_obj = self.get_request_from_view_args( func, args, kwargs) parsed_args = None if as_kwargs: kwargs.update(parsed_args) return func(*args, **kwargs) else: # Add parsed_args after other positional arguments new_args = args + (parsed_args, ) return func(*new_args, **kwargs) return wrapper return decorator
def test_argmap2schema(): argmap = { 'id': fields.Int(required=True), 'title': fields.Str(), 'description': fields.Str(), 'content_type': fields.Str(load_from='content-type') } schema_cls = argmap2schema(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 assert schema.opts.strict is True
def test_delimited_list_as_string_v2(web_request, parser): web_request.json = {"dates": "2018-11-01,2018-11-02"} schema_cls = argmap2schema({ "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"
def use_args(self, argmap, req=None, locations=None, as_kwargs=False, validate=None): """Decorator that injects parsed arguments into a view function or method. .. warning:: This will not work with `async def` coroutines. Either use a generator-based coroutine decorated with `asyncio.coroutine` or use the `parse <webargs.async.AsyncParser.parse>` 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, collections.Mapping): argmap = core.argmap2schema(argmap)() def decorator(func): req_ = request_obj @functools.wraps(func) def wrapper(*args, **kwargs): req_obj = req_ # if as_kwargs is passed, must include all args force_all = as_kwargs 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(argmap, req=req_obj, locations=locations, validate=validate, force_all=force_all) if as_kwargs: kwargs.update(parsed_args) return func(*args, **kwargs) else: # Add parsed_args after other positional arguments new_args = args + (parsed_args, ) return func(*new_args, **kwargs) return wrapper return decorator
def use_args(self, argmap, req=None, locations=core.Parser.DEFAULT_LOCATIONS, as_kwargs=False, validate=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 tuple locations: Where on the request to search for 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`. """ locations = locations or self.locations # Optimization: If argmap is passed as a dictionary, we only need # to generate a Schema once if isinstance(argmap, collections.Mapping): argmap = core.argmap2schema(argmap)() 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, locations=locations, validate=validate, force_all=as_kwargs) if as_kwargs: kwargs.update(parsed_args) return func(obj, *args, **kwargs) else: return func(obj, parsed_args, *args, **kwargs) return wrapper return decorator
def use_args(self, argmap, req=None, locations=None, as_kwargs=False, validate=None): """Decorator that injects parsed arguments into a view function or method. .. warning:: This will not work with `async def` coroutines. Either use a generator-based coroutine decorated with `asyncio.coroutine` or use the `parse <webargs.async.AsyncParser.parse>` method. Receives the same arguments as `webargs.core.Parser.use_args`. """ locations = locations or self.locations if isinstance(argmap, ma.Schema): schema = argmap else: schema = core.argmap2schema(argmap)() request_obj = req def decorator(func): req_ = request_obj @functools.wraps(func) def wrapper(*args, **kwargs): req_obj = req_ # if as_kwargs is passed, must include all args force_all = as_kwargs if not req_obj: req_obj = self.get_request_from_view_args(func, args, kwargs) parsed_args = None if as_kwargs: kwargs.update(parsed_args) return func(*args, **kwargs) else: # Add parsed_args after other positional arguments new_args = args + (parsed_args, ) return func(*new_args, **kwargs) return wrapper return decorator
def test_argmap2schema(): 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 = argmap2schema(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
def test_argmap2schema(): 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 = argmap2schema(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
def use_args(self, argmap, req=None, locations=core.Parser.DEFAULT_LOCATIONS, as_kwargs=False, validate=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` or a `dict` of argname -> `marshmallow.fields.Field` pairs. :param req: The request object to parse. Pulled off of the view by default. :param tuple locations: Where on the request to search for 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`. """ locations = locations or self.locations if isinstance(argmap, ma.Schema): schema = argmap else: schema = core.argmap2schema(argmap)() 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 parsed_args = self.parse(schema, req=request, locations=locations, validate=validate, force_all=as_kwargs) if as_kwargs: kwargs.update(parsed_args) return func(obj, *args, **kwargs) else: return func(obj, parsed_args, *args, **kwargs) return wrapper return decorator
def __init__(self, nested, *args, **kwargs): if isinstance(nested, dict): nested = argmap2schema(nested) super(Nested, self).__init__(nested, *args, **kwargs)
def get_schema(argmap): if isinstance(argmap, Schema): return argmap else: return argmap2schema(argmap)()