Skip to content

Commit e348106

Browse files
authored
fix(flags): Don't override existing props when adding flags (#110)
1 parent e60d52c commit e348106

File tree

4 files changed

+92
-36
lines changed

4 files changed

+92
-36
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 3.3.1 - 2024-01-10
2+
3+
1. Make sure we don't override any existing feature flag properties when adding locally evaluated feature flag properties.
4+
15
## 3.3.0 - 2024-01-09
26

37
1. When local evaluation is enabled, we automatically add flag information to all events sent to PostHog, whenever possible. This makes it easier to use these events in experiments.

posthog/client.py

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -137,16 +137,6 @@ def get_feature_variants(
137137
resp_data = self.get_decide(distinct_id, groups, person_properties, group_properties, disable_geoip)
138138
return resp_data["featureFlags"]
139139

140-
def _get_active_feature_variants(
141-
self, distinct_id, groups=None, person_properties=None, group_properties=None, disable_geoip=None
142-
):
143-
feature_variants = self.get_feature_variants(
144-
distinct_id, groups, person_properties, group_properties, disable_geoip
145-
)
146-
return {
147-
k: v for (k, v) in feature_variants.items() if v is not False
148-
} # explicitly test for false to account for values that may seem falsy (ex: 0)
149-
150140
def get_feature_payloads(
151141
self, distinct_id, groups=None, person_properties=None, group_properties=None, disable_geoip=None
152142
):
@@ -206,26 +196,29 @@ def capture(
206196
require("groups", groups, dict)
207197
msg["properties"]["$groups"] = groups
208198

199+
extra_properties = {}
200+
feature_variants = {}
209201
if send_feature_flags:
210202
try:
211-
feature_variants = self._get_active_feature_variants(distinct_id, groups, disable_geoip=disable_geoip)
203+
feature_variants = self.get_feature_variants(distinct_id, groups, disable_geoip=disable_geoip)
212204
except Exception as e:
213205
self.log.exception(f"[FEATURE FLAGS] Unable to get feature variants: {e}")
214-
else:
215-
for feature, variant in feature_variants.items():
216-
msg["properties"][f"$feature/{feature}"] = variant
217-
msg["properties"]["$active_feature_flags"] = list(feature_variants.keys())
206+
218207
elif self.feature_flags:
219208
# Local evaluation is enabled, flags are loaded, so try and get all flags we can without going to the server
220209
feature_variants = self.get_all_flags(
221210
distinct_id, groups=(groups or {}), disable_geoip=disable_geoip, only_evaluate_locally=True
222211
)
223-
for feature, variant in feature_variants.items():
224-
msg["properties"][f"$feature/{feature}"] = variant
225212

226-
active_feature_flags = [key for (key, value) in feature_variants.items() if value is not False]
227-
if active_feature_flags:
228-
msg["properties"]["$active_feature_flags"] = active_feature_flags
213+
for feature, variant in feature_variants.items():
214+
extra_properties[f"$feature/{feature}"] = variant
215+
216+
active_feature_flags = [key for (key, value) in feature_variants.items() if value is not False]
217+
if active_feature_flags:
218+
extra_properties["$active_feature_flags"] = active_feature_flags
219+
220+
if extra_properties:
221+
msg["properties"] = {**extra_properties, **msg["properties"]}
229222

230223
return self._enqueue(msg, disable_geoip)
231224

posthog/test/test_client.py

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -210,24 +210,83 @@ def test_basic_capture_with_locally_evaluated_feature_flags(self, patch_decide):
210210
assert "$active_feature_flags" not in msg["properties"]
211211

212212
@mock.patch("posthog.client.decide")
213-
def test_get_active_feature_flags(self, patch_decide):
214-
patch_decide.return_value = {
215-
"featureFlags": {"beta-feature": "random-variant", "alpha-feature": True, "off-feature": False}
213+
def test_dont_override_capture_with_local_flags(self, patch_decide):
214+
patch_decide.return_value = {"featureFlags": {"beta-feature": "random-variant"}}
215+
client = Client(FAKE_TEST_API_KEY, on_error=self.set_fail, personal_api_key=FAKE_TEST_API_KEY)
216+
217+
multivariate_flag = {
218+
"id": 1,
219+
"name": "Beta Feature",
220+
"key": "beta-feature-local",
221+
"is_simple_flag": False,
222+
"active": True,
223+
"rollout_percentage": 100,
224+
"filters": {
225+
"groups": [
226+
{
227+
"properties": [
228+
{"key": "email", "type": "person", "value": "[email protected]", "operator": "exact"}
229+
],
230+
"rollout_percentage": 100,
231+
},
232+
{
233+
"rollout_percentage": 50,
234+
},
235+
],
236+
"multivariate": {
237+
"variants": [
238+
{"key": "first-variant", "name": "First Variant", "rollout_percentage": 50},
239+
{"key": "second-variant", "name": "Second Variant", "rollout_percentage": 25},
240+
{"key": "third-variant", "name": "Third Variant", "rollout_percentage": 25},
241+
]
242+
},
243+
"payloads": {"first-variant": "some-payload", "third-variant": {"a": "json"}},
244+
},
216245
}
246+
basic_flag = {
247+
"id": 1,
248+
"name": "Beta Feature",
249+
"key": "person-flag",
250+
"is_simple_flag": True,
251+
"active": True,
252+
"filters": {
253+
"groups": [
254+
{
255+
"properties": [
256+
{
257+
"key": "region",
258+
"operator": "exact",
259+
"value": ["USA"],
260+
"type": "person",
261+
}
262+
],
263+
"rollout_percentage": 100,
264+
}
265+
],
266+
"payloads": {"true": 300},
267+
},
268+
}
269+
client.feature_flags = [multivariate_flag, basic_flag]
217270

218-
client = Client(FAKE_TEST_API_KEY, on_error=self.set_fail, personal_api_key=FAKE_TEST_API_KEY)
219-
variants = client._get_active_feature_variants("some_id", None, None, None, False)
220-
self.assertEqual(variants, {"beta-feature": "random-variant", "alpha-feature": True})
221-
patch_decide.assert_called_with(
222-
"random_key",
223-
None,
224-
timeout=10,
225-
distinct_id="some_id",
226-
groups={},
227-
person_properties=None,
228-
group_properties=None,
229-
disable_geoip=False,
271+
success, msg = client.capture(
272+
"distinct_id", "python test event", {"$feature/beta-feature-local": "my-custom-variant"}
230273
)
274+
client.flush()
275+
self.assertTrue(success)
276+
self.assertFalse(self.failed)
277+
278+
self.assertEqual(msg["event"], "python test event")
279+
self.assertTrue(isinstance(msg["timestamp"], str))
280+
self.assertIsNone(msg.get("uuid"))
281+
self.assertEqual(msg["distinct_id"], "distinct_id")
282+
self.assertEqual(msg["properties"]["$lib"], "posthog-python")
283+
self.assertEqual(msg["properties"]["$lib_version"], VERSION)
284+
self.assertEqual(msg["properties"]["$feature/beta-feature-local"], "my-custom-variant")
285+
self.assertEqual(msg["properties"]["$active_feature_flags"], ["beta-feature-local"])
286+
assert "$feature/beta-feature" not in msg["properties"]
287+
assert "$feature/person-flag" not in msg["properties"]
288+
289+
self.assertEqual(patch_decide.call_count, 0)
231290

232291
@mock.patch("posthog.client.decide")
233292
def test_basic_capture_with_feature_flags_returns_active_only(self, patch_decide):

posthog/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION = "3.3.0"
1+
VERSION = "3.3.1"
22

33
if __name__ == "__main__":
44
print(VERSION, end="") # noqa: T201

0 commit comments

Comments
 (0)