|
1 | | -import re |
| 1 | +from importlib import util |
| 2 | +from pathlib import Path |
| 3 | +import types |
2 | 4 | from typing import Any, Literal |
3 | 5 |
|
4 | 6 | from entitled.exceptions import AuthorizationException |
5 | 7 | from entitled.policies import Policy |
6 | 8 | from entitled.response import Err, Response |
7 | | -from entitled.rules import Actor, Rule, RuleProto |
8 | 9 |
|
9 | 10 |
|
10 | 11 | class Client: |
11 | | - def __init__(self): |
12 | | - self._policy_registry: dict[type, Policy[Any]] = {} |
13 | | - self._rule_registry: dict[str, Rule[Any]] = {} |
| 12 | + load_path: Path | None = None |
| 13 | + _policy_registry: dict[type, Policy[Any]] |
14 | 14 |
|
15 | | - def define_rule(self, name: str, callable: RuleProto[Actor]) -> Rule[Actor]: |
16 | | - rule = Rule(name, callable) |
17 | | - self._rule_registry[rule.name] = rule |
18 | | - return rule |
| 15 | + def __init__(self, path: str | None = None): |
| 16 | + self._policy_registry = dict() |
| 17 | + if path is not None: |
| 18 | + self.load_path = Path(path) |
| 19 | + self.load_policies() |
19 | 20 |
|
20 | 21 | def register_policy(self, policy: Policy[Any]): |
21 | 22 | resource_type = getattr(policy, "__orig_class__").__args__[0] |
22 | 23 | self._policy_registry[resource_type] = policy |
23 | 24 |
|
| 25 | + def load_policies(self, path: Path | None = None): |
| 26 | + path = path if path is not None else self.load_path |
| 27 | + if path is None: |
| 28 | + return |
| 29 | + for file in path.glob("*.py"): |
| 30 | + mod_name = file.stem |
| 31 | + full_mod_name = ".".join(file.parts[:-1] + (mod_name,)) |
| 32 | + spec = util.spec_from_file_location(full_mod_name, file) |
| 33 | + if spec is not None: |
| 34 | + mod = util.module_from_spec(spec) |
| 35 | + if spec.loader: |
| 36 | + try: |
| 37 | + spec.loader.exec_module(mod) |
| 38 | + self._register_from_module(mod) |
| 39 | + except Exception as e: |
| 40 | + raise e |
| 41 | + |
| 42 | + def _register_from_module(self, mod: types.ModuleType): |
| 43 | + for attr_name in dir(mod): |
| 44 | + attr = getattr(mod, attr_name) |
| 45 | + if isinstance(attr, Policy): |
| 46 | + try: |
| 47 | + self.register_policy(attr) |
| 48 | + except (ValueError, AttributeError): |
| 49 | + pass |
| 50 | + |
24 | 51 | def _resolve_policy(self, resource: Any) -> Policy[Any] | None: |
25 | 52 | lookup_key = resource if isinstance(resource, type) else type(resource) |
26 | 53 | policy = self._policy_registry.get(lookup_key, None) |
|
0 commit comments