Skip to content

Commit 237dfa2

Browse files
committed
feat: use the variant as the exposure event value
When `get_experiment_flag` records a `$flag_exposure` event, send the selected variant as the event value when present (the variant's key, or "control" for the control bucket), falling back to the flag value for standard flags. This identifies the experiment cohort without changing the event shape.
1 parent f15af26 commit 237dfa2

2 files changed

Lines changed: 72 additions & 2 deletions

File tree

flagsmith/flagsmith.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,11 +362,11 @@ def get_experiment_flag(
362362
if not self._event_processor:
363363
raise ValueError("Events must be enabled to use experiment flags.")
364364
flag = self.get_identity_flags(identifier, traits).get_flag(feature_name)
365-
if not flag.is_default:
365+
if isinstance(flag, Flag):
366366
self.track_exposure_event(
367367
feature_name=feature_name,
368368
identifier=identifier,
369-
value=flag.value,
369+
value=flag.variant if flag.variant is not None else flag.value,
370370
traits=traits,
371371
)
372372
return flag

tests/test_flagsmith.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,3 +1116,73 @@ def default_flag_handler(feature_name: str) -> DefaultFlag:
11161116
assert result.is_default is True
11171117
assert result.value == "default-variant"
11181118
mock_track.assert_not_called()
1119+
1120+
1121+
def test_get_experiment_flag_uses_variant_as_exposure_value(
1122+
mocker: MockerFixture, api_key: str
1123+
) -> None:
1124+
# Given - a resolved flag carrying a variant
1125+
config = EventProcessorConfig(events_api_url="http://test/")
1126+
flagsmith = Flagsmith(
1127+
environment_key=api_key, enable_events=True, event_processor_config=config
1128+
)
1129+
flag = Flag(
1130+
enabled=True,
1131+
value="blue",
1132+
feature_name="checkout_v2",
1133+
feature_id=1,
1134+
variant="control",
1135+
)
1136+
mocker.patch.object(
1137+
flagsmith,
1138+
"get_identity_flags",
1139+
return_value=Flags(flags={"checkout_v2": flag}),
1140+
)
1141+
mock_track = mocker.patch.object(flagsmith._event_processor, "track_exposure_event")
1142+
1143+
# When
1144+
flagsmith.get_experiment_flag(feature_name="checkout_v2", identifier="user1")
1145+
1146+
# Then - the exposure value is the variant, not the flag value
1147+
mock_track.assert_called_once_with(
1148+
feature_name="checkout_v2",
1149+
identifier="user1",
1150+
value="control",
1151+
traits=None,
1152+
metadata=None,
1153+
)
1154+
1155+
1156+
def test_get_experiment_flag_falls_back_to_value_without_variant(
1157+
mocker: MockerFixture, api_key: str
1158+
) -> None:
1159+
# Given - a resolved flag with no variant
1160+
config = EventProcessorConfig(events_api_url="http://test/")
1161+
flagsmith = Flagsmith(
1162+
environment_key=api_key, enable_events=True, event_processor_config=config
1163+
)
1164+
flag = Flag(
1165+
enabled=True,
1166+
value="blue",
1167+
feature_name="checkout_v2",
1168+
feature_id=1,
1169+
variant=None,
1170+
)
1171+
mocker.patch.object(
1172+
flagsmith,
1173+
"get_identity_flags",
1174+
return_value=Flags(flags={"checkout_v2": flag}),
1175+
)
1176+
mock_track = mocker.patch.object(flagsmith._event_processor, "track_exposure_event")
1177+
1178+
# When
1179+
flagsmith.get_experiment_flag(feature_name="checkout_v2", identifier="user1")
1180+
1181+
# Then - the exposure value falls back to the flag value
1182+
mock_track.assert_called_once_with(
1183+
feature_name="checkout_v2",
1184+
identifier="user1",
1185+
value="blue",
1186+
traits=None,
1187+
metadata=None,
1188+
)

0 commit comments

Comments
 (0)