|
8 | 8 | from devcycle_python_sdk.api.local_bucketing import LocalBucketing |
9 | 9 | from devcycle_python_sdk.exceptions import VariableTypeMismatchError |
10 | 10 | from devcycle_python_sdk.managers.config_manager import EnvironmentConfigManager |
| 11 | +from devcycle_python_sdk.managers.eval_hooks_manager import ( |
| 12 | + EvalHooksManager, |
| 13 | + BeforeHookError, |
| 14 | + AfterHookError, |
| 15 | +) |
11 | 16 | from devcycle_python_sdk.managers.event_queue_manager import EventQueueManager |
12 | 17 | from devcycle_python_sdk.models.bucketed_config import BucketedConfig |
| 18 | +from devcycle_python_sdk.models.eval_hook import EvalHook |
| 19 | +from devcycle_python_sdk.models.eval_hook_context import HookContext |
13 | 20 | from devcycle_python_sdk.models.event import DevCycleEvent, EventType |
14 | 21 | from devcycle_python_sdk.models.feature import Feature |
15 | 22 | from devcycle_python_sdk.models.platform_data import default_platform_data |
@@ -51,6 +58,7 @@ def __init__(self, sdk_key: str, options: DevCycleLocalOptions): |
51 | 58 | ) |
52 | 59 |
|
53 | 60 | self._openfeature_provider: Optional[DevCycleProvider] = None |
| 61 | + self.eval_hooks_manager = EvalHooksManager(self.options.eval_hooks) |
54 | 62 |
|
55 | 63 | def get_sdk_platform(self) -> str: |
56 | 64 | return "Local" |
@@ -133,18 +141,44 @@ def variable(self, user: DevCycleUser, key: str, default_value: Any) -> Variable |
133 | 141 | ) |
134 | 142 | return Variable.create_default_variable(key, default_value) |
135 | 143 |
|
| 144 | + context = HookContext(key, user, default_value) |
| 145 | + variable = Variable.create_default_variable( |
| 146 | + key=key, default_value=default_value |
| 147 | + ) |
| 148 | + |
136 | 149 | try: |
| 150 | + before_hook_error = None |
| 151 | + try: |
| 152 | + context = self.eval_hooks_manager.run_before(context) |
| 153 | + except BeforeHookError as e: |
| 154 | + before_hook_error = e |
137 | 155 | variable = self.local_bucketing.get_variable_for_user_protobuf( |
138 | 156 | user, key, default_value |
139 | 157 | ) |
140 | | - if variable: |
141 | | - return variable |
| 158 | + if variable is None: |
| 159 | + variable = Variable.create_default_variable( |
| 160 | + key=key, default_value=default_value |
| 161 | + ) |
| 162 | + |
| 163 | + if before_hook_error is None: |
| 164 | + self.eval_hooks_manager.run_after(context, variable) |
| 165 | + else: |
| 166 | + raise before_hook_error |
142 | 167 | except VariableTypeMismatchError: |
143 | 168 | logger.debug("DevCycle: Variable type mismatch, returning default value") |
| 169 | + return variable |
| 170 | + except BeforeHookError as e: |
| 171 | + self.eval_hooks_manager.run_error(context, e) |
| 172 | + return variable |
| 173 | + except AfterHookError as e: |
| 174 | + self.eval_hooks_manager.run_error(context, e) |
| 175 | + return variable |
144 | 176 | except Exception as e: |
145 | 177 | logger.warning(f"DevCycle: Error retrieving variable for user: {e}") |
146 | | - |
147 | | - return Variable.create_default_variable(key, default_value) |
| 178 | + return variable |
| 179 | + finally: |
| 180 | + self.eval_hooks_manager.run_finally(context, variable) |
| 181 | + return variable |
148 | 182 |
|
149 | 183 | def _generate_bucketed_config(self, user: DevCycleUser) -> BucketedConfig: |
150 | 184 | """ |
@@ -234,6 +268,12 @@ def close(self) -> None: |
234 | 268 | self.config_manager.close() |
235 | 269 | self.event_queue_manager.close() |
236 | 270 |
|
| 271 | + def add_hook(self, eval_hook: EvalHook) -> None: |
| 272 | + self.eval_hooks_manager.add_hook(eval_hook) |
| 273 | + |
| 274 | + def clear_hooks(self) -> None: |
| 275 | + self.eval_hooks_manager.clear_hooks() |
| 276 | + |
237 | 277 |
|
238 | 278 | def _validate_sdk_key(sdk_key: str) -> None: |
239 | 279 | if sdk_key is None or len(sdk_key) == 0: |
|
0 commit comments