def _add_missing_time(field, data, time_): ds = dict2schema({field: fields.Date()})() dts = dict2schema({field: NaiveDateTime()})() try: # let's see if we can load this as a DateTime dts.load({field: data[field]}) except ValidationError: # if not, we assume it's a valid date and append the time date = ds.load({field: data[field]})[field] data[field] = dts.dump({field: datetime.combine(date, time_)})[field]
def use_rh_args(schema_cls, **kwargs): """Similar to ``use_args`` but populates the context from RH attributes. The Schema needs a Meta class with an ``rh_context`` attribute specifying which attributes should be taken from the current RH. :param schema_cls: A marshmallow Schema or an argmap dict. :param rh_context: When using an argmap, this argument is required and behaves exactly like the ``rh_context`` Meta attribute mentioned above. :param kwargs: Any keyword arguments that are supported by ``use_args`` or the Schema constructor. """ schema_kwargs, default_context, webargs_kwargs = _split_kwargs(kwargs) if isinstance(schema_cls, Mapping): schema_cls = dict2schema(schema_cls, parser.schema_class) rh_context_attrs = schema_kwargs.pop('rh_context') elif isinstance(schema_cls, Schema): raise TypeError('Pass a schema or an argmap instead of a schema instance to use_rh_args/use_rh_kwargs') else: if 'rh_context' in schema_kwargs: raise TypeError('The `rh_context` kwarg is only supported when passing an argmap') rh_context_attrs = schema_cls.Meta.rh_context def factory(req): context = dict(default_context) context.update((arg, getattr(g.rh, arg, None)) for arg in rh_context_attrs) return schema_cls(context=context, **schema_kwargs) return parser.use_args(factory, **webargs_kwargs)
def use_args(schema_cls, **kwargs): """Similar to webargs' ``use_args`` but allows passing schema kwargs. This makes it much easier to use ``partial=True`` for PATCH endpoints. :param schema_cls: A marshmallow Schema or an argmap dict. :param kwargs: Any keyword arguments that are supported by ``use_args`` or the Schema constructor. """ schema_kwargs, __, webargs_kwargs = _split_kwargs(kwargs) if isinstance(schema_cls, Mapping): schema_cls = dict2schema(schema_cls, parser.schema_class) elif isinstance(schema_cls, Schema): raise TypeError('Pass a schema or an argmap instead of a schema instance to use_args/use_kwargs') def factory(req): return schema_cls(**schema_kwargs) return parser.use_args(factory, **webargs_kwargs)
def test_load_json_returns_missing_if_no_data(mimetype): req = mock.Mock() req.mimetype = mimetype req.get_data.return_value = "" schema = dict2schema({"foo": fields.Field()})() assert parser.load_json(req, schema) is missing
def make_route(input_args: dict = None, output_args: dict = None, locations: tuple = None, validate: object = None, path: str = None, auth_required: callable = None, method_types: int = None): """ Functions makes the route for wrapped function. :param input_args: Map of incoming data scheme :param output_args: Map of output scheme :param locations: Location of incoming data ('form', 'data', 'json') :param validate: Validator of full scheme :param path: Stringify path of decorated async function :param auth_required: This functions checks credential information inside request headers :param method_types: This flags indicates about methods for specific endpoint :return: callable """ if not isinstance(method_types, int): method_types = GET | POST # Prepare dumper for outgoing data # if not (isinstance(output_args, dict) or isinstance(output_args, list)): # output_args = {'result': fields.List(fields.Str(), missing=[])} if isinstance(output_args, dict): schema = dict2schema(output_args)() else: schema = output_args() # Checking locations of data # for incoming request if not isinstance(locations, tuple): locations = ('json', 'querystring') def wrapped(fn_: callable): # Create the wrapper for original # async coroutine function @wraps(fn_) async def coro_wrapper(request: web.Request): # First checking authorization auth_data = None if inspect.iscoroutinefunction(auth_required): auth_data = await auth_required(request) # Parsing incoming data using parser and # scheme of input arguments parsed_data_map = dict() if input_args: parsed_data_map = await aiohttpparser.parser.parse( input_args, request, locations, validate ) # Injecting data from request's header # data if auth_data: parsed_data_map = {**parsed_data_map, **auth_data} # Waiting the result from original function # and dumping it data = await fn_(**{**parsed_data_map, **{'request': request}}) if isinstance(data, (web.FileResponse, web.WebSocketResponse, web.Response)): return data # 1) Validating outgoing data scheme # 2) Serialize verified data if data is None: data = {} else: if isinstance(output_args, dict): if not isinstance(data, tuple): data = (data,) data = dict(zip(output_args.keys(), data)) return JSON_RESPONSE( schema.dump(data) ) # Last thing is dispatch the route of # aiohttp coroutine and it endpoint endpoint_path = path if not isinstance(endpoint_path, str): # First step is extract # name of called module frm = inspect.stack()[1] mod = inspect.getmodule(frm[0]) # This module name should # exclude from global path root_file = __name__ # The full path to wrapped # resource endpoint resource_path = mod.__name__ resource_path = resource_path.replace(root_file, '') resource_path = resource_path.replace('.', '/') # Extract endpoint name method_name = __to_camel(fn_.__name__) endpoint_path = "/{0}.{1}".format(resource_path, method_name) # Add coroutine wrapper inside the webapp if (method_types & GET) == GET: ROUTE_TABLE.append( web.get(endpoint_path, coro_wrapper, allow_head=False) ) if (method_types & POST) == POST: ROUTE_TABLE.append( web.post(endpoint_path, coro_wrapper) ) if fn_.__doc__: coro_wrapper = docs( tags=[resource_path.split('/')[-1]], summary=fn_.__doc__ )(coro_wrapper) if schema: coro_wrapper = response_schema(schema)(coro_wrapper) if input_args: coro_wrapper = request_schema(input_args)(coro_wrapper) return coro_wrapper return wrapped