Skip to content

Commit 7f3df9a

Browse files
committed
refactor!: rename open_feature.hooks module to hook
Signed-off-by: Federico Bond <[email protected]>
1 parent 1dfbf29 commit 7f3df9a

15 files changed

+143
-13
lines changed

open_feature/hooks/hook_support.py renamed to open_feature/_internal/hook_support.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from open_feature.evaluation_context import EvaluationContext
66
from open_feature.flag_evaluation import FlagEvaluationDetails, FlagType
7-
from open_feature.hooks import Hook, HookContext, HookType
7+
from open_feature.hook import Hook, HookContext, HookType
88

99

1010
def error_hooks(

open_feature/api.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from open_feature.client import OpenFeatureClient
44
from open_feature.evaluation_context import EvaluationContext
55
from open_feature.exception import GeneralError
6-
from open_feature.hooks import Hook
6+
from open_feature.hook import Hook
77
from open_feature.provider.metadata import Metadata
88
from open_feature.provider.no_op_provider import NoOpProvider
99
from open_feature.provider.provider import AbstractProvider

open_feature/client.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
Reason,
1818
FlagResolutionDetails,
1919
)
20-
from open_feature.hooks import Hook, HookContext
21-
from open_feature.hooks.hook_support import (
20+
from open_feature.hook import Hook, HookContext
21+
from open_feature.hook.hook_support import (
2222
after_all_hooks,
2323
after_hooks,
2424
before_hooks,

open_feature/flag_evaluation.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from open_feature.exception import ErrorCode
77

88
if typing.TYPE_CHECKING: # resolves a circular dependency in type annotations
9-
from open_feature.hooks import Hook
9+
from open_feature.hook import Hook
1010

1111

1212
class FlagType(StrEnum):
File renamed without changes.

open_feature/hook/hook_support.py

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import logging
2+
import typing
3+
from functools import reduce
4+
5+
from open_feature.evaluation_context import EvaluationContext
6+
from open_feature.flag_evaluation import FlagEvaluationDetails, FlagType
7+
from open_feature.hook import Hook, HookContext, HookType
8+
9+
10+
def error_hooks(
11+
flag_type: FlagType,
12+
hook_context: HookContext,
13+
exception: Exception,
14+
hooks: typing.List[Hook],
15+
hints: typing.Optional[typing.Mapping] = None,
16+
):
17+
kwargs = {"hook_context": hook_context, "exception": exception, "hints": hints}
18+
_execute_hooks(
19+
flag_type=flag_type, hooks=hooks, hook_method=HookType.ERROR, **kwargs
20+
)
21+
22+
23+
def after_all_hooks(
24+
flag_type: FlagType,
25+
hook_context: HookContext,
26+
hooks: typing.List[Hook],
27+
hints: typing.Optional[typing.Mapping] = None,
28+
):
29+
kwargs = {"hook_context": hook_context, "hints": hints}
30+
_execute_hooks(
31+
flag_type=flag_type, hooks=hooks, hook_method=HookType.FINALLY_AFTER, **kwargs
32+
)
33+
34+
35+
def after_hooks(
36+
flag_type: FlagType,
37+
hook_context: HookContext,
38+
details: FlagEvaluationDetails,
39+
hooks: typing.List[Hook],
40+
hints: typing.Optional[typing.Mapping] = None,
41+
):
42+
kwargs = {"hook_context": hook_context, "details": details, "hints": hints}
43+
_execute_hooks_unchecked(
44+
flag_type=flag_type, hooks=hooks, hook_method=HookType.AFTER, **kwargs
45+
)
46+
47+
48+
def before_hooks(
49+
flag_type: FlagType,
50+
hook_context: HookContext,
51+
hooks: typing.List[Hook],
52+
hints: typing.Optional[typing.Mapping] = None,
53+
) -> EvaluationContext:
54+
kwargs = {"hook_context": hook_context, "hints": hints}
55+
executed_hooks = _execute_hooks_unchecked(
56+
flag_type=flag_type, hooks=hooks, hook_method=HookType.BEFORE, **kwargs
57+
)
58+
filtered_hooks = list(filter(lambda hook: hook is not None, executed_hooks))
59+
60+
if filtered_hooks:
61+
return reduce(lambda a, b: a.merge(b), filtered_hooks)
62+
63+
return EvaluationContext()
64+
65+
66+
def _execute_hooks(
67+
flag_type: FlagType, hooks: typing.List[Hook], hook_method: HookType, **kwargs
68+
) -> list:
69+
"""
70+
Run multiple hooks of any hook type. All of these hooks will be run through an
71+
exception check.
72+
73+
:param flag_type: particular type of flag
74+
:param hooks: a list of hooks
75+
:param hook_method: the type of hook that is being run
76+
:param kwargs: arguments that need to be provided to the hook method
77+
:return: a list of results from the applied hook methods
78+
"""
79+
if hooks:
80+
filtered_hooks = list(
81+
filter(
82+
lambda hook: hook.supports_flag_value_type(flag_type=flag_type), hooks
83+
)
84+
)
85+
return [
86+
_execute_hook_checked(hook, hook_method, **kwargs)
87+
for hook in filtered_hooks
88+
]
89+
return []
90+
91+
92+
def _execute_hooks_unchecked(
93+
flag_type: FlagType, hooks, hook_method: HookType, **kwargs
94+
) -> list:
95+
"""
96+
Execute a single hook without checking whether an exception is thrown. This is
97+
used in the before and after hooks since any exception will be caught in the
98+
client.
99+
100+
:param flag_type: particular type of flag
101+
:param hooks: a list of hooks
102+
:param hook_method: the type of hook that is being run
103+
:param kwargs: arguments that need to be provided to the hook method
104+
:return: a list of results from the applied hook methods
105+
"""
106+
if hooks:
107+
filtered_hooks = list(
108+
filter(
109+
lambda hook: hook.supports_flag_value_type(flag_type=flag_type), hooks
110+
)
111+
)
112+
return [getattr(hook, hook_method.value)(**kwargs) for hook in filtered_hooks]
113+
114+
return []
115+
116+
117+
def _execute_hook_checked(hook: Hook, hook_method: HookType, **kwargs):
118+
"""
119+
Try and run a single hook and catch any exception thrown. This is used in the
120+
after all and error hooks since any error thrown at this point needs to be caught.
121+
122+
:param hook: a list of hooks
123+
:param hook_method: the type of hook that is being run
124+
:param kwargs: arguments that need to be provided to the hook method
125+
:return: the result of the hook method
126+
"""
127+
try:
128+
return getattr(hook, hook_method.value)(**kwargs)
129+
except Exception: # noqa
130+
logging.error(f"Exception when running {hook_method.value} hooks")

open_feature/provider/in_memory_provider.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from open_feature.evaluation_context import EvaluationContext
66
from open_feature.exception import ErrorCode
77
from open_feature.flag_evaluation import FlagResolutionDetails, Reason
8-
from open_feature.hooks import Hook
8+
from open_feature.hook import Hook
99
from open_feature.provider.metadata import Metadata
1010
from open_feature.provider.provider import AbstractProvider
1111

open_feature/provider/no_op_provider.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from open_feature.evaluation_context import EvaluationContext
44
from open_feature.flag_evaluation import FlagResolutionDetails, Reason
5-
from open_feature.hooks import Hook
5+
from open_feature.hook import Hook
66
from open_feature.provider.metadata import Metadata
77
from open_feature.provider.no_op_metadata import NoOpMetadata
88
from open_feature.provider.provider import AbstractProvider

open_feature/provider/provider.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from open_feature.evaluation_context import EvaluationContext
55
from open_feature.flag_evaluation import FlagResolutionDetails
6-
from open_feature.hooks import Hook
6+
from open_feature.hook import Hook
77
from open_feature.provider.metadata import Metadata
88

99

readme.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ See [here](https://openfeature.dev/ecosystem) for a catalog of available provide
142142
A hook is a mechanism that allows for adding arbitrary behavior at well-defined points of the flag evaluation life-cycle. Use cases include validating the resolved flag value, modifying or adding data to the evaluation context, logging, telemetry, and tracking.
143143

144144
```python
145-
from open_feature.hooks import Hook
145+
from open_feature.hook import Hook
146146

147147
class MyHook(Hook):
148148
def after(self, hook_context: HookContext, details: FlagEvaluationDetails, hints: dict):
File renamed without changes.
File renamed without changes.

tests/hooks/test_hook_support.py renamed to tests/hook/test_hook_support.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from unittest.mock import ANY
22

33
from open_feature.flag_evaluation import FlagEvaluationDetails, FlagType
4-
from open_feature.hooks import HookContext
5-
from open_feature.hooks.hook_support import (
4+
from open_feature.hook import HookContext
5+
from open_feature.hook.hook_support import (
66
after_all_hooks,
77
after_hooks,
88
before_hooks,

tests/test_api.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
)
1616
from open_feature.evaluation_context import EvaluationContext
1717
from open_feature.exception import ErrorCode, GeneralError
18-
from open_feature.hooks import Hook
18+
from open_feature.hook import Hook
1919
from open_feature.provider.metadata import Metadata
2020
from open_feature.provider.no_op_provider import NoOpProvider
2121

tests/test_client.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from open_feature.client import OpenFeatureClient
77
from open_feature.exception import ErrorCode, OpenFeatureError
88
from open_feature.flag_evaluation import Reason
9-
from open_feature.hooks import Hook
9+
from open_feature.hook import Hook
1010
from open_feature.provider.no_op_provider import NoOpProvider
1111

1212

0 commit comments

Comments
 (0)