Reputation: 2795
I want to achieve a simple interface as such:
IsAllowed(perms=[IsAdmin(runtime_value) | HasPerm('*')])
Since some variables upon instantiation are not available, I have to postpone the evaluation of perms=[IsAdmin() | HasPerm('*')]
to later point in time (when __call__
is called on IsAllowed by the FastAPI webframework I'm using). The closest I have come to achieving that is the following:
IsAllowed(perms = lambda runtime_value: [IsAdmin(runtime_value) | HasPerm('*')])
class IsAllowed(object):
def __init__(self, perms=None):
self.perms = perms
def __call__(self, runtime_value):
result = self.perms(runtime_value)
return result
No my question is, is there any way to keep the interface as IsAllowed(perms=[IsAdmin(runtime_value) | HasPerm('*')])
but, somehow inject the lambda
into it before instantiation?
I am thinking of maybe metaclasses or leveraging the __init_subclass__
hook?
Any ideas?
Upvotes: 3
Views: 59
Reputation: 542
If I understood your question correctly, you want something like that:
from typing import Any
class IsAllowed(object):
def __init__(self, *perms):
self.perms = perms
def __call__(self, args: list[Any]):
return all(self.perms[i](args[i]) for i in range(len(args)))
checker = IsAllowed(IsAdmin, HasPerm)
checker(“somevalue”, “*”)
UPDATE:
For the cases mentioned in the comment section:
from typing import Any, Callable
class Operation:
pass
class Or(Operation):
def __init__(self, *funcs: Callable[[Any], bool]) -> None:
self.funcs = funcs
def __call__(self, val: Any) -> bool:
return any(func(val) for func in self.funcs)
def __or__(self, other: Operation) -> Operation:
return Or(*self.funcs, other.func)
class Predicate:
def __init__(self, func: Callable[[Any], bool]) -> None:
self.func = func
def __or__(self, other) -> Or:
return Or(self.func, other.func)
def Is1(x: int) -> bool:
return x == 1
def Is2(x: int) -> bool:
return x == 2
def Is3(x: int) -> bool:
return x == 3
def main() -> None:
pred1 = Predicate(Is1)
pred2 = Predicate(Is2)
pred3 = Predicate(Is3)
fancy_pred = pred1 | pred2 | pred3
for i in range(5):
print(fancy_pred(i))
if __name__ == "__main__":
main()
Upvotes: 1