def _install_request_parser_annotation(f, base_generic_type: Type): handler_type_hints = get_handler_original_typehints(f) path_params: List[RequestParserAnnotationSpec] = [] for name, _type in handler_type_hints.items(): if is_base_type(_type, base_generic_type): generic_type_args = get_args(_type) if not generic_type_args: raise TypeError( f"{base_generic_type} must be Generic Type. Your handler {get_handler_original_qualname(f)} declares a parametrer that's not {base_generic_type}[T]" ) if generic_type_args: path_params.append( RequestParserAnnotationSpec(name=name, base=_type, arg_type=generic_type_args[0])) @wraps(f) async def _wrap(wrapper: RequestWrapper): for p in path_params: try: typed_val = await p.base.from_request(request=wrapper, arg_name=p.name, arg_type=p.arg_type) wrapper.types_registry.set(typed_val, p.base, param_name=p.name) except ValueError as e: raise HTTPBadRequest(text=e.args[0]) return await call_http_handler(wrapper, f) return _wrap
async def test_does_not_have_attribute(self): def func(a: int, b: bool): pass self.assertEqual( get_handler_original_typehints(func), {"a": int, "b": bool} ) self.assertFalse(hasattr(func, "asyncworker_original_annotations"))
async def test_with_one_first_decorator(self): @handler_register @_deco async def _func(q: int, b: bool): pass final_func = await _func() self.assertEqual(final_func.__annotations__, {"s": str}) self.assertEqual( get_handler_original_typehints(final_func), {"q": int, "b": bool} ) self.assertEqual( "TestWrapsDecorator.test_with_one_first_decorator.<locals>._func", final_func.asyncworker_original_qualname, )
async def test_with_three_decorators(self): @handler_register @_deco3 @_deco2 @_deco async def _func(other: int, integer: int, feature: bool): pass final_func = await _func() self.assertEqual( final_func.__annotations__, {"flag": bool, "other": str} ) self.assertEqual( get_handler_original_typehints(final_func), {"other": int, "integer": int, "feature": bool}, )
async def test_with_two_second_decorators(self): @handler_register @_deco2 @_deco async def _func(other: int, integer: int, feature: bool): pass final_func = await _func() self.assertEqual(final_func.__annotations__, {"param": bool, "i": int}) self.assertEqual( get_handler_original_typehints(final_func), {"other": int, "integer": int, "feature": bool}, ) self.assertEqual( "TestWrapsDecorator.test_with_two_second_decorators.<locals>._func", final_func.asyncworker_original_qualname, )
def parse_path(handler): """ Decorator que permite receber dinamicamente parametros do Request Path Basta que o nome do parametro na assinatura do handler seja igual ao nome do parametro declarado no Path HTTP. """ """ Aqui usamos essa função `_dummy` apenas para aproveitar a implementação já existente em `typing.get_type_hints()`. Como essa implementação exige que passamos uma function, mas temos nesse momento apenas um dict. Então criamos essa função "vazia" e colocmos nela as anotações do handler original. """ handler_types_args = get_handler_original_typehints(handler) handler_args_names = list(handler_types_args.keys()) @wraps(handler) async def _wrap(wrapper: RequestWrapper): req = wrapper.http_request for param_name in handler_args_names: if param_name in req.match_info: try: value = handler_types_args[param_name]( req.match_info[param_name]) wrapper.types_registry.set(value, param_name=param_name) except ValueError: await logger.exception({ "event": "incompatible-types-handler-arg", "arg-type": handler_types_args[param_name], "arg-value": req.match_info[param_name], }) raise return await call_http_handler(wrapper, handler) return _wrap
async def test_when_decorator_has_parameters(self): def _deco_with_params(a: int): def _wrap1(handler): @wraps(handler) async def _final_wrap(param: bool): pass return _final_wrap return _wrap1 @handler_register @_deco_with_params(42) async def _func(x: bool, y: int): pass final_func = await _func() self.assertEqual(final_func.__annotations__, {"param": bool}) self.assertEqual( get_handler_original_typehints(final_func), {"x": bool, "y": int} )
async def test_is_base_when_not_generic(self): def _func(b: MyGeneric): pass _type = get_handler_original_typehints(_func) self.assertTrue(is_base_type(_type["b"], MyGeneric))
async def _wrap(): return get_handler_original_typehints(handler)
async def test_is_base_when_arg_primitive_base_generic(self): def _func(b: int): pass _type = get_handler_original_typehints(_func) self.assertFalse(is_base_type(_type["b"], MyGeneric))