Source code for guardrail.core.decorators

# -*- coding: utf-8 -*-

import functools


AGENT_NOT_FOUND = 'agent_not_found'
TARGET_NOT_FOUND = 'target_not_found'
FORBIDDEN = 'forbidden'


[docs]class has_permission(object): """Factory for permission-checking decorators. Should be subclassed or have arguments pre-filled with `functools.partial`. :param permission: Permission value :param manager: Permission manager :param agent_loader: Callable that loads an agent from the `args` and `kwargs` passed to the decorated function :param target_loader: Callable that loads a target from the `args` and `kwargs` passed to the decorated function :param error_handler: Callable that handles error codes `AGENT_NOT_FOUND`, `TARGET_NOT_FOUND`, and `FORBIDDEN` """ def __init__(self, permission, manager, agent_loader, target_loader, error_handler): self.permission = permission self.manager = manager self.agent_loader = agent_loader self.target_loader = target_loader self.error_handler = error_handler
[docs] def __call__(self, func): """Decorator that checks permissions before calling `func`. Note: wrapped function will be called with the loaded agent and target. :param func: Callable to decorate """ @functools.wraps(func) def wrapped(*args, **kwargs): agent, target = self._check_permission(*args, **kwargs) kwargs.update({ 'agent': agent, 'target': target, }) return func(*args, **kwargs) return wrapped
[docs] def _check_permission(self, *args, **kwargs): """Load agent and target records from `agent_loader` and `target_loader`, then check for the requested permission. Call `error_handler` if either loader returns `None`, or if permission is not present. """ agent = self.agent_loader(*args, **kwargs) if not agent: return self.error_handler(AGENT_NOT_FOUND) target = self.target_loader(*args, **kwargs) if not target: return self.error_handler(TARGET_NOT_FOUND) if not self.manager.has_permission(agent, target, self.permission): self.error_handler(FORBIDDEN) return agent, target