Skip to content

Commit 6910859

Browse files
committed
haha okay
1 parent 1b57a96 commit 6910859

File tree

2 files changed

+61
-5
lines changed

2 files changed

+61
-5
lines changed

posthog/client.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,9 @@ def get_feature_flag(
714714
if self.disabled:
715715
return None
716716

717+
# Normalize key to lowercase
718+
key = str(key).lower()
719+
717720
person_properties, group_properties = self._add_local_person_and_group_properties(
718721
distinct_id, groups, person_properties, group_properties
719722
)
@@ -724,7 +727,8 @@ def get_feature_flag(
724727

725728
if self.feature_flags:
726729
for flag in self.feature_flags:
727-
if flag["key"] == key:
730+
# Compare lowercase keys
731+
if str(flag["key"]).lower() == key:
728732
try:
729733
response = self._compute_flag_locally(
730734
flag,
@@ -855,10 +859,18 @@ def _compute_payload_locally(self, key, match_value):
855859
if self.feature_flags_by_key is None:
856860
return payload
857861

858-
flag_definition = self.feature_flags_by_key.get(key) or {}
859-
flag_filters = flag_definition.get("filters") or {}
860-
flag_payloads = flag_filters.get("payloads") or {}
861-
payload = flag_payloads.get(str(match_value).lower(), None)
862+
# Normalize key to lowercase when looking up flag definition
863+
key = str(key).lower()
864+
flag_definition = None
865+
for flag_key, flag in self.feature_flags_by_key.items():
866+
if str(flag_key).lower() == key:
867+
flag_definition = flag
868+
break
869+
870+
if flag_definition:
871+
flag_filters = flag_definition.get("filters") or {}
872+
flag_payloads = flag_filters.get("payloads") or {}
873+
payload = flag_payloads.get(str(match_value).lower(), None)
862874
return payload
863875

864876
def get_all_flags(

posthog/test/test_feature_flags.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4640,3 +4640,47 @@ def test_multivariate_flag_consistency(self, patch_get):
46404640
self.assertEqual(feature_flag_match, results[i])
46414641
else:
46424642
self.assertFalse(feature_flag_match)
4643+
4644+
@mock.patch("posthog.client.decide")
4645+
def test_feature_flag_case_insensitive(self, mock_decide):
4646+
client = Client(api_key=FAKE_TEST_API_KEY, personal_api_key=FAKE_TEST_API_KEY)
4647+
client.feature_flags = [
4648+
{
4649+
"id": 1,
4650+
"key": "Beta-Feature",
4651+
"active": True,
4652+
"filters": {
4653+
"groups": [{"properties": [], "rollout_percentage": 100}],
4654+
},
4655+
}
4656+
]
4657+
4658+
# Test that flag evaluation works regardless of case
4659+
self.assertTrue(client.feature_enabled("Beta-Feature", "user1"))
4660+
self.assertTrue(client.feature_enabled("beta-feature", "user1"))
4661+
self.assertTrue(client.feature_enabled("BETA-FEATURE", "user1"))
4662+
4663+
@mock.patch("posthog.client.decide")
4664+
def test_feature_flag_mixed_case_consistency(self, mock_decide):
4665+
client = Client(api_key=FAKE_TEST_API_KEY, personal_api_key=FAKE_TEST_API_KEY)
4666+
client.feature_flags = [
4667+
{
4668+
"id": 1,
4669+
"key": "Beta-Feature",
4670+
"active": True,
4671+
"filters": {
4672+
"groups": [{"properties": [], "rollout_percentage": 100}],
4673+
"payloads": {
4674+
"true": {"some": "value"},
4675+
}
4676+
},
4677+
}
4678+
]
4679+
4680+
# Test that flag evaluation and payload retrieval are consistent
4681+
# regardless of the case used
4682+
test_cases = ["Beta-Feature", "beta-feature", "BETA-FEATURE", "bEtA-FeAtUrE"]
4683+
4684+
for case in test_cases:
4685+
# Both the flag evaluation and payload retrieval should work
4686+
self.assertTrue(client.feature_enabled(case, "user1"))

0 commit comments

Comments
 (0)