from typing import Any, Callable, Dict, List
[docs]
def before_request(
hook: Callable[[], Any] = None, only: List[str] = None
) -> Callable[..., Any]:
"""
This decorator provides a way to hook into the request
lifecycle by enqueueing methods to be invoked before
each handler in the view. If the method returns a value
other than :code:`None`, then that value will be returned
to the client. If invoked with the :code:`only` kwarg,
the hook will only be invoked for the given list of
handler methods.
Examples::
class MyFeature(ModelView)
@before_request
def ensure_feature_is_enabled(self):
if self.feature_is_disabled:
return self.response_404()
return None
# etc...
class MyView(ModelRestAPI):
@before_request(only=["create", "update", "delete"])
def ensure_write_mode_enabled(self):
if self.read_only:
return self.response_400()
return None
# etc...
:param hook:
A callable to be invoked before handlers in the class. If the
hook returns :code:`None`, then the request proceeds and the
handler is invoked. If it returns something other than :code:`None`,
then execution halts and that value is returned to the client.
:param only:
An optional list of the names of handler methods. If present,
:code:`hook` will only be invoked before the handlers specified
in the list. If absent, :code:`hook` will be invoked for before
all handlers in the class.
"""
def wrap(hook: Callable[[], Any]) -> Callable[[], Any]:
hook._before_request_hook = True
hook._before_request_only = only
return hook
return wrap if hook is None else wrap(hook)
def wrap_route_handler_with_hooks(
handler_name: str,
handler: Callable[..., Any],
before_request_hooks: List[Callable[[], Any]],
) -> Callable[..., Any]:
applicable_hooks = []
for hook in before_request_hooks:
only = hook._before_request_only
applicable_hook = only is None or handler_name in only
if applicable_hook:
applicable_hooks.append(hook)
if not applicable_hooks:
return handler
def wrapped_handler(*args: List[Any], **kwargs: Dict[str, Any]) -> Any:
for hook in applicable_hooks:
result = hook()
if result is not None:
return result
return handler(*args, **kwargs)
return wrapped_handler
def get_before_request_hooks(view_or_api_instance: Any) -> List[Callable[[], Any]]:
before_request_hooks = []
for attr_name in dir(view_or_api_instance):
attr = getattr(view_or_api_instance, attr_name)
if hasattr(attr, "_before_request_hook") and attr._before_request_hook is True:
before_request_hooks.append(attr)
return before_request_hooks