77Actors represents any entity that, in an application, can act upon a resource.
88"""
99
10- from typing import Any , Callable , ClassVar , Generic , Protocol , TypeVar
10+ import inspect
11+ from typing import Any , Callable , ClassVar , Generic , Protocol , TypeVar , cast
1112
1213from entitled import exceptions
1314
1415Resource = TypeVar ("Resource" , contravariant = True )
1516
1617
17- class RuleProtocol (Protocol [Resource ]):
18+ class SyncRule (Protocol [Resource ]):
1819 """Defines valid functions for rules"""
1920
2021 def __call__ (
@@ -25,6 +26,34 @@ def __call__(
2526 ) -> bool : ...
2627
2728
29+ class AsyncRule (Protocol [Resource ]):
30+ """Defines valid functions for rules"""
31+
32+ async def __call__ (
33+ self ,
34+ actor : Any ,
35+ resource : Resource | type [Resource ],
36+ context : dict [str , Any ] | None = None ,
37+ ) -> bool : ...
38+
39+
40+ RuleProtocol = SyncRule [Resource ] | AsyncRule [Resource ]
41+
42+
43+ async def handle_rule (
44+ func : AsyncRule [Resource ] | SyncRule [Resource ],
45+ actor : Any ,
46+ resource : Resource | type [Resource ],
47+ context : dict [str , Any ] | None = None ,
48+ ):
49+ if inspect .iscoroutinefunction (func ):
50+ fn = cast (AsyncRule [Resource ], func )
51+ return await fn (actor , resource , context )
52+ else :
53+ fn = cast (SyncRule [Resource ], func )
54+ return fn (actor , resource , context )
55+
56+
2857class Rule (Generic [Resource ]):
2958 """Base class for rules
3059
@@ -55,33 +84,33 @@ def __register(self) -> None:
5584
5685 Rule ._registry [self .name ] = self
5786
58- def __call__ (
87+ async def __call__ (
5988 self ,
6089 actor : Any ,
6190 resource : Resource | type [Resource ],
6291 context : dict [str , Any ] | None = None ,
6392 ) -> bool :
6493 if not context :
6594 context = {}
66- return self .rule ( actor , resource , context )
95+ return await handle_rule ( self .rule , actor , resource , context )
6796
68- def authorize (
97+ async def authorize (
6998 self ,
7099 actor : Any ,
71100 resource : Resource | type [Resource ],
72101 context : dict [str , Any ] | None = None ,
73102 ) -> bool :
74- if not self (actor , resource , context ):
103+ if not await self (actor , resource , context ):
75104 raise exceptions .AuthorizationException ("Unauthorized" )
76105 return True
77106
78- def allows (
107+ async def allows (
79108 self ,
80109 actor : Any ,
81110 resource : Resource | type [Resource ],
82111 context : dict [str , Any ] | None = None ,
83112 ) -> bool :
84- return self (actor , resource , context )
113+ return await self (actor , resource , context )
85114
86115
87116def rule (name : str ) -> Callable [[RuleProtocol [Resource ]], RuleProtocol [Resource ]]:
0 commit comments