Skip to content

Commit 3b89760

Browse files
authored
feat: make specific fields in HookContext immutable (#266)
make specific fields in HookContext immutable Signed-off-by: gruebel <[email protected]>
1 parent 5ef6ca1 commit 3b89760

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

openfeature/hook/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ class HookContext:
2929
client_metadata: typing.Optional[ClientMetadata] = None
3030
provider_metadata: typing.Optional[Metadata] = None
3131

32+
def __setattr__(self, key: str, value: typing.Any) -> None:
33+
if hasattr(self, key) and key in ("flag_key", "flag_type", "default_value"):
34+
raise AttributeError(f"Attribute {key!r} is immutable")
35+
super().__setattr__(key, value)
36+
3237

3338
class Hook:
3439
def before(

tests/hook/test_hook_support.py

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

3+
import pytest
4+
5+
from openfeature.client import ClientMetadata
36
from openfeature.evaluation_context import EvaluationContext
47
from openfeature.flag_evaluation import FlagEvaluationDetails, FlagType
58
from openfeature.hook import Hook, HookContext
@@ -10,6 +13,57 @@
1013
error_hooks,
1114
)
1215
from openfeature.immutable_dict.mapping_proxy_type import MappingProxyType
16+
from openfeature.provider.metadata import Metadata
17+
18+
19+
def test_hook_context_has_required_and_optional_fields():
20+
"""Requirement
21+
22+
4.1.1 - Hook context MUST provide: the "flag key", "flag value type", "evaluation context", and the "default value".
23+
4.1.2 - The "hook context" SHOULD provide: access to the "client metadata" and the "provider metadata" fields.
24+
"""
25+
26+
# Given/When
27+
hook_context = HookContext("flag_key", FlagType.BOOLEAN, True, EvaluationContext())
28+
29+
# Then
30+
assert hasattr(hook_context, "flag_key")
31+
assert hasattr(hook_context, "flag_type")
32+
assert hasattr(hook_context, "default_value")
33+
assert hasattr(hook_context, "evaluation_context")
34+
assert hasattr(hook_context, "client_metadata")
35+
assert hasattr(hook_context, "provider_metadata")
36+
37+
38+
def test_hook_context_has_immutable_and_mutable_fields():
39+
"""Requirement
40+
41+
4.1.3 - The "flag key", "flag type", and "default value" properties MUST be immutable.
42+
4.1.4.1 - The evaluation context MUST be mutable only within the before hook.
43+
"""
44+
45+
# Given
46+
hook_context = HookContext("flag_key", FlagType.BOOLEAN, True, EvaluationContext())
47+
48+
# When
49+
with pytest.raises(AttributeError):
50+
hook_context.flag_key = "new_key"
51+
with pytest.raises(AttributeError):
52+
hook_context.flag_type = FlagType.STRING
53+
with pytest.raises(AttributeError):
54+
hook_context.default_value = "new_value"
55+
56+
hook_context.evaluation_context = EvaluationContext("targeting_key")
57+
hook_context.client_metadata = ClientMetadata("name")
58+
hook_context.provider_metadata = Metadata("name")
59+
60+
# Then
61+
assert hook_context.flag_key == "flag_key"
62+
assert hook_context.flag_type is FlagType.BOOLEAN
63+
assert hook_context.default_value is True
64+
assert hook_context.evaluation_context.targeting_key == "targeting_key"
65+
assert hook_context.client_metadata.name == "name"
66+
assert hook_context.provider_metadata.name == "name"
1367

1468

1569
def test_error_hooks_run_error_method(mock_hook):

0 commit comments

Comments
 (0)