Compare commits

...
1 Commits
Author SHA1 Message Date
617bb53501 Disable geoip for capture and decide calls by default (#98)
Co-authored-by: Neil Kakkar <neilkakkar@gmail.com>
2023-04-17 12:06:57 +01:00
6 changed files with 305 additions and 29 deletions
+19
View File
@@ -1,3 +1,22 @@
## 3.0.0 - 2023-04-14
Breaking change:
All events by default now send the `$geoip_disable` property to disable geoip lookup in app. This is because usually we don't
want to update person properties to take the server's location.
The same now happens for feature flag requests, where we discard the IP address of the server for matching on geoip properties like city, country, continent.
To restore previous behaviour, you can set the default to False like so:
```python
posthog.disable_geoip = False
# // and if using client instantiation:
posthog = Posthog('api_key', disable_geoip=False)
```
## 2.5.0 - 2023-04-10
1. Add option for instantiating separate client object
+24
View File
@@ -17,6 +17,7 @@ disabled = False # type: bool
personal_api_key = None # type: str
project_api_key = None # type: str
poll_interval = 30 # type: int
disable_geoip = True # type: bool
default_client = None
@@ -30,6 +31,7 @@ def capture(
uuid=None, # type: Optional[str]
groups=None, # type: Optional[Dict]
send_feature_flags=False,
disable_geoip=None, # type: Optional[bool]
):
# type: (...) -> None
"""
@@ -62,6 +64,7 @@ def capture(
uuid=uuid,
groups=groups,
send_feature_flags=send_feature_flags,
disable_geoip=disable_geoip,
)
@@ -71,6 +74,7 @@ def identify(
context=None, # type: Optional[Dict]
timestamp=None, # type: Optional[datetime.datetime]
uuid=None, # type: Optional[str]
disable_geoip=None, # type: Optional[bool]
):
# type: (...) -> None
"""
@@ -95,6 +99,7 @@ def identify(
context=context,
timestamp=timestamp,
uuid=uuid,
disable_geoip=disable_geoip,
)
@@ -104,6 +109,7 @@ def set(
context=None, # type: Optional[Dict]
timestamp=None, # type: Optional[datetime.datetime]
uuid=None, # type: Optional[str]
disable_geoip=None, # type: Optional[bool]
):
# type: (...) -> None
"""
@@ -128,6 +134,7 @@ def set(
context=context,
timestamp=timestamp,
uuid=uuid,
disable_geoip=disable_geoip,
)
@@ -137,6 +144,7 @@ def set_once(
context=None, # type: Optional[Dict]
timestamp=None, # type: Optional[datetime.datetime]
uuid=None, # type: Optional[str]
disable_geoip=None, # type: Optional[bool]
):
# type: (...) -> None
"""
@@ -161,6 +169,7 @@ def set_once(
context=context,
timestamp=timestamp,
uuid=uuid,
disable_geoip=disable_geoip,
)
@@ -171,6 +180,7 @@ def group_identify(
context=None, # type: Optional[Dict]
timestamp=None, # type: Optional[datetime.datetime]
uuid=None, # type: Optional[str]
disable_geoip=None, # type: Optional[bool]
):
# type: (...) -> None
"""
@@ -196,6 +206,7 @@ def group_identify(
context=context,
timestamp=timestamp,
uuid=uuid,
disable_geoip=disable_geoip,
)
@@ -205,6 +216,7 @@ def alias(
context=None, # type: Optional[Dict]
timestamp=None, # type: Optional[datetime.datetime]
uuid=None, # type: Optional[str]
disable_geoip=None, # type: Optional[bool]
):
# type: (...) -> None
"""
@@ -230,6 +242,7 @@ def alias(
context=context,
timestamp=timestamp,
uuid=uuid,
disable_geoip=disable_geoip,
)
@@ -241,6 +254,7 @@ def feature_enabled(
group_properties={}, # type: dict
only_evaluate_locally=False, # type: bool
send_feature_flag_events=True, # type: bool
disable_geoip=None, # type: Optional[bool]
):
# type: (...) -> bool
"""
@@ -265,6 +279,7 @@ def feature_enabled(
group_properties=group_properties,
only_evaluate_locally=only_evaluate_locally,
send_feature_flag_events=send_feature_flag_events,
disable_geoip=disable_geoip,
)
@@ -276,6 +291,7 @@ def get_feature_flag(
group_properties={}, # type: dict
only_evaluate_locally=False, # type: bool
send_feature_flag_events=True, # type: bool
disable_geoip=None, # type: Optional[bool]
):
"""
Get feature flag variant for users. Used with experiments.
@@ -308,6 +324,7 @@ def get_feature_flag(
group_properties=group_properties,
only_evaluate_locally=only_evaluate_locally,
send_feature_flag_events=send_feature_flag_events,
disable_geoip=disable_geoip,
)
@@ -317,6 +334,7 @@ def get_all_flags(
person_properties={}, # type: dict
group_properties={}, # type: dict
only_evaluate_locally=False, # type: bool
disable_geoip=None, # type: Optional[bool]
):
"""
Get all flags for a given user.
@@ -334,6 +352,7 @@ def get_all_flags(
person_properties=person_properties,
group_properties=group_properties,
only_evaluate_locally=only_evaluate_locally,
disable_geoip=disable_geoip,
)
@@ -346,6 +365,7 @@ def get_feature_flag_payload(
group_properties={},
only_evaluate_locally=False,
send_feature_flag_events=True,
disable_geoip=None, # type: Optional[bool]
):
return _proxy(
"get_feature_flag_payload",
@@ -357,6 +377,7 @@ def get_feature_flag_payload(
group_properties=group_properties,
only_evaluate_locally=only_evaluate_locally,
send_feature_flag_events=send_feature_flag_events,
disable_geoip=disable_geoip,
)
@@ -366,6 +387,7 @@ def get_all_flags_and_payloads(
person_properties={},
group_properties={},
only_evaluate_locally=False,
disable_geoip=None, # type: Optional[bool]
):
return _proxy(
"get_all_flags_and_payloads",
@@ -374,6 +396,7 @@ def get_all_flags_and_payloads(
person_properties=person_properties,
group_properties=group_properties,
only_evaluate_locally=only_evaluate_locally,
disable_geoip=disable_geoip,
)
@@ -418,6 +441,7 @@ def _proxy(method, *args, **kwargs):
project_api_key=project_api_key,
poll_interval=poll_interval,
disabled=disabled,
disable_geoip=disable_geoip,
)
# always set incase user changes it
+90 -27
View File
@@ -48,6 +48,7 @@ class Client(object):
personal_api_key=None,
project_api_key=None,
disabled=False,
disable_geoip=True,
):
self.queue = queue.Queue(max_queue_size)
@@ -71,6 +72,7 @@ class Client(object):
self.poller = None
self.distinct_ids_feature_flags_reported = SizeLimitedDict(MAX_DICT_SIZE, set)
self.disabled = disabled
self.disable_geoip = disable_geoip
# personal_api_key: This should be a generated Personal API Key, private
self.personal_api_key = personal_api_key
@@ -112,7 +114,7 @@ class Client(object):
if send:
consumer.start()
def identify(self, distinct_id=None, properties=None, context=None, timestamp=None, uuid=None):
def identify(self, distinct_id=None, properties=None, context=None, timestamp=None, uuid=None, disable_geoip=None):
properties = properties or {}
context = context or {}
require("distinct_id", distinct_id, ID_TYPES)
@@ -127,25 +129,36 @@ class Client(object):
"uuid": uuid,
}
return self._enqueue(msg)
return self._enqueue(msg, disable_geoip)
def get_feature_variants(self, distinct_id, groups=None, person_properties=None, group_properties=None):
resp_data = self.get_decide(distinct_id, groups, person_properties, group_properties)
def get_feature_variants(
self, distinct_id, groups=None, person_properties=None, group_properties=None, disable_geoip=None
):
resp_data = self.get_decide(distinct_id, groups, person_properties, group_properties, disable_geoip)
return resp_data["featureFlags"]
def _get_active_feature_variants(self, distinct_id, groups=None, person_properties=None, group_properties=None):
feature_variants = self.get_feature_variants(distinct_id, groups, person_properties, group_properties)
def _get_active_feature_variants(
self, distinct_id, groups=None, person_properties=None, group_properties=None, disable_geoip=None
):
feature_variants = self.get_feature_variants(
distinct_id, groups, person_properties, group_properties, disable_geoip
)
return {
k: v for (k, v) in feature_variants.items() if v is not False
} # explicitly test for false to account for values that may seem falsy (ex: 0)
def get_feature_payloads(self, distinct_id, groups=None, person_properties=None, group_properties=None):
resp_data = self.get_decide(distinct_id, groups, person_properties, group_properties)
def get_feature_payloads(
self, distinct_id, groups=None, person_properties=None, group_properties=None, disable_geoip=None
):
resp_data = self.get_decide(distinct_id, groups, person_properties, group_properties, disable_geoip)
return resp_data["featureFlagPayloads"]
def get_decide(self, distinct_id, groups=None, person_properties=None, group_properties=None):
def get_decide(self, distinct_id, groups=None, person_properties=None, group_properties=None, disable_geoip=None):
require("distinct_id", distinct_id, ID_TYPES)
if disable_geoip is None:
disable_geoip = self.disable_geoip
if groups:
require("groups", groups, dict)
else:
@@ -156,6 +169,7 @@ class Client(object):
"groups": groups,
"person_properties": person_properties,
"group_properties": group_properties,
"disable_geoip": disable_geoip,
}
resp_data = decide(self.api_key, self.host, timeout=10, **request_data)
@@ -171,6 +185,7 @@ class Client(object):
uuid=None,
groups=None,
send_feature_flags=False,
disable_geoip=None,
):
properties = properties or {}
context = context or {}
@@ -193,7 +208,7 @@ class Client(object):
if send_feature_flags:
try:
feature_variants = self._get_active_feature_variants(distinct_id, groups)
feature_variants = self._get_active_feature_variants(distinct_id, groups, disable_geoip=disable_geoip)
except Exception as e:
self.log.exception(f"[FEATURE FLAGS] Unable to get feature variants: {e}")
else:
@@ -201,9 +216,9 @@ class Client(object):
msg["properties"]["$feature/{}".format(feature)] = variant
msg["properties"]["$active_feature_flags"] = list(feature_variants.keys())
return self._enqueue(msg)
return self._enqueue(msg, disable_geoip)
def set(self, distinct_id=None, properties=None, context=None, timestamp=None, uuid=None):
def set(self, distinct_id=None, properties=None, context=None, timestamp=None, uuid=None, disable_geoip=None):
properties = properties or {}
context = context or {}
require("distinct_id", distinct_id, ID_TYPES)
@@ -218,9 +233,9 @@ class Client(object):
"uuid": uuid,
}
return self._enqueue(msg)
return self._enqueue(msg, disable_geoip)
def set_once(self, distinct_id=None, properties=None, context=None, timestamp=None, uuid=None):
def set_once(self, distinct_id=None, properties=None, context=None, timestamp=None, uuid=None, disable_geoip=None):
properties = properties or {}
context = context or {}
require("distinct_id", distinct_id, ID_TYPES)
@@ -235,9 +250,18 @@ class Client(object):
"uuid": uuid,
}
return self._enqueue(msg)
return self._enqueue(msg, disable_geoip)
def group_identify(self, group_type=None, group_key=None, properties=None, context=None, timestamp=None, uuid=None):
def group_identify(
self,
group_type=None,
group_key=None,
properties=None,
context=None,
timestamp=None,
uuid=None,
disable_geoip=None,
):
properties = properties or {}
context = context or {}
require("group_type", group_type, ID_TYPES)
@@ -257,9 +281,9 @@ class Client(object):
"uuid": uuid,
}
return self._enqueue(msg)
return self._enqueue(msg, disable_geoip)
def alias(self, previous_id=None, distinct_id=None, context=None, timestamp=None, uuid=None):
def alias(self, previous_id=None, distinct_id=None, context=None, timestamp=None, uuid=None, disable_geoip=None):
context = context or {}
require("previous_id", previous_id, ID_TYPES)
@@ -276,9 +300,11 @@ class Client(object):
"distinct_id": previous_id,
}
return self._enqueue(msg)
return self._enqueue(msg, disable_geoip)
def page(self, distinct_id=None, url=None, properties=None, context=None, timestamp=None, uuid=None):
def page(
self, distinct_id=None, url=None, properties=None, context=None, timestamp=None, uuid=None, disable_geoip=None
):
properties = properties or {}
context = context or {}
@@ -297,9 +323,9 @@ class Client(object):
"uuid": uuid,
}
return self._enqueue(msg)
return self._enqueue(msg, disable_geoip)
def _enqueue(self, msg):
def _enqueue(self, msg, disable_geoip):
"""Push a new `msg` onto the queue, return `(success, msg)`"""
if self.disabled:
@@ -327,6 +353,12 @@ class Client(object):
msg["properties"]["$lib"] = "posthog-python"
msg["properties"]["$lib_version"] = VERSION
if disable_geoip is None:
disable_geoip = self.disable_geoip
if disable_geoip:
msg["properties"]["$geoip_disable"] = True
msg["distinct_id"] = stringify_id(msg.get("distinct_id", None))
msg = clean(msg)
@@ -470,6 +502,7 @@ class Client(object):
group_properties={},
only_evaluate_locally=False,
send_feature_flag_events=True,
disable_geoip=None,
):
response = self.get_feature_flag(
key,
@@ -479,6 +512,7 @@ class Client(object):
group_properties=group_properties,
only_evaluate_locally=only_evaluate_locally,
send_feature_flag_events=send_feature_flag_events,
disable_geoip=disable_geoip,
)
if response is None:
@@ -495,6 +529,7 @@ class Client(object):
group_properties={},
only_evaluate_locally=False,
send_feature_flag_events=True,
disable_geoip=None,
):
require("key", key, string_types)
require("distinct_id", distinct_id, ID_TYPES)
@@ -528,7 +563,11 @@ class Client(object):
if not flag_was_locally_evaluated and not only_evaluate_locally:
try:
feature_flags = self.get_feature_variants(
distinct_id, groups=groups, person_properties=person_properties, group_properties=group_properties
distinct_id,
groups=groups,
person_properties=person_properties,
group_properties=group_properties,
disable_geoip=disable_geoip,
)
response = feature_flags.get(key)
if response is None:
@@ -551,6 +590,7 @@ class Client(object):
"locally_evaluated": flag_was_locally_evaluated,
},
groups=groups,
disable_geoip=disable_geoip,
)
self.distinct_ids_feature_flags_reported[distinct_id].add(feature_flag_reported_key)
return response
@@ -566,6 +606,7 @@ class Client(object):
group_properties={},
only_evaluate_locally=False,
send_feature_flag_events=True,
disable_geoip=None,
):
if match_value is None:
match_value = self.get_feature_flag(
@@ -576,6 +617,7 @@ class Client(object):
group_properties=group_properties,
send_feature_flag_events=send_feature_flag_events,
only_evaluate_locally=True,
disable_geoip=disable_geoip,
)
response = None
@@ -584,7 +626,9 @@ class Client(object):
response = self._compute_payload_locally(key, match_value)
if response is None and not only_evaluate_locally:
decide_payloads = self.get_feature_payloads(distinct_id, groups, person_properties, group_properties)
decide_payloads = self.get_feature_payloads(
distinct_id, groups, person_properties, group_properties, disable_geoip
)
response = decide_payloads.get(str(key).lower(), None)
return response
@@ -602,7 +646,14 @@ class Client(object):
return payload
def get_all_flags(
self, distinct_id, *, groups={}, person_properties={}, group_properties={}, only_evaluate_locally=False
self,
distinct_id,
*,
groups={},
person_properties={},
group_properties={},
only_evaluate_locally=False,
disable_geoip=None,
):
flags = self.get_all_flags_and_payloads(
distinct_id,
@@ -610,11 +661,19 @@ class Client(object):
person_properties=person_properties,
group_properties=group_properties,
only_evaluate_locally=only_evaluate_locally,
disable_geoip=disable_geoip,
)
return flags["featureFlags"]
def get_all_flags_and_payloads(
self, distinct_id, *, groups={}, person_properties={}, group_properties={}, only_evaluate_locally=False
self,
distinct_id,
*,
groups={},
person_properties={},
group_properties={},
only_evaluate_locally=False,
disable_geoip=None,
):
flags, payloads, fallback_to_decide = self._get_all_flags_and_payloads_locally(
distinct_id, groups=groups, person_properties=person_properties, group_properties=group_properties
@@ -624,7 +683,11 @@ class Client(object):
if fallback_to_decide and not only_evaluate_locally:
try:
flags_and_payloads = self.get_decide(
distinct_id, groups=groups, person_properties=person_properties, group_properties=group_properties
distinct_id,
groups=groups,
person_properties=person_properties,
group_properties=group_properties,
disable_geoip=disable_geoip,
)
response = flags_and_payloads
except Exception as e:
+129 -1
View File
@@ -112,8 +112,18 @@ class TestClient(unittest.TestCase):
}
client = Client(FAKE_TEST_API_KEY, on_error=self.set_fail, personal_api_key=FAKE_TEST_API_KEY)
variants = client._get_active_feature_variants("some_id", None, None, None)
variants = client._get_active_feature_variants("some_id", None, None, None, False)
self.assertEqual(variants, {"beta-feature": "random-variant", "alpha-feature": True})
patch_decide.assert_called_with(
"random_key",
None,
timeout=10,
distinct_id="some_id",
groups={},
person_properties=None,
group_properties=None,
disable_geoip=False,
)
@mock.patch("posthog.client.decide")
def test_basic_capture_with_feature_flags_returns_active_only(self, patch_decide):
@@ -131,6 +141,7 @@ class TestClient(unittest.TestCase):
self.assertTrue(isinstance(msg["timestamp"], str))
self.assertIsNone(msg.get("uuid"))
self.assertEqual(msg["distinct_id"], "distinct_id")
self.assertTrue(msg["properties"]["$geoip_disable"])
self.assertEqual(msg["properties"]["$lib"], "posthog-python")
self.assertEqual(msg["properties"]["$lib_version"], VERSION)
self.assertEqual(msg["properties"]["$feature/beta-feature"], "random-variant")
@@ -138,6 +149,53 @@ class TestClient(unittest.TestCase):
self.assertEqual(msg["properties"]["$active_feature_flags"], ["beta-feature", "alpha-feature"])
self.assertEqual(patch_decide.call_count, 1)
patch_decide.assert_called_with(
"random_key",
None,
timeout=10,
distinct_id="distinct_id",
groups={},
person_properties=None,
group_properties=None,
disable_geoip=True,
)
@mock.patch("posthog.client.decide")
def test_basic_capture_with_feature_flags_and_disable_geoip_returns_correctly(self, patch_decide):
patch_decide.return_value = {
"featureFlags": {"beta-feature": "random-variant", "alpha-feature": True, "off-feature": False}
}
client = Client(
FAKE_TEST_API_KEY, on_error=self.set_fail, personal_api_key=FAKE_TEST_API_KEY, disable_geoip=True
)
success, msg = client.capture("distinct_id", "python test event", send_feature_flags=True, disable_geoip=False)
client.flush()
self.assertTrue(success)
self.assertFalse(self.failed)
self.assertEqual(msg["event"], "python test event")
self.assertTrue(isinstance(msg["timestamp"], str))
self.assertIsNone(msg.get("uuid"))
self.assertTrue("$geoip_disable" not in msg["properties"])
self.assertEqual(msg["distinct_id"], "distinct_id")
self.assertEqual(msg["properties"]["$lib"], "posthog-python")
self.assertEqual(msg["properties"]["$lib_version"], VERSION)
self.assertEqual(msg["properties"]["$feature/beta-feature"], "random-variant")
self.assertEqual(msg["properties"]["$feature/alpha-feature"], True)
self.assertEqual(msg["properties"]["$active_feature_flags"], ["beta-feature", "alpha-feature"])
self.assertEqual(patch_decide.call_count, 1)
patch_decide.assert_called_with(
"random_key",
None,
timeout=10,
distinct_id="distinct_id",
groups={},
person_properties=None,
group_properties=None,
disable_geoip=False,
)
@mock.patch("posthog.client.decide")
def test_basic_capture_with_feature_flags_switched_off_doesnt_send_them(self, patch_decide):
@@ -305,6 +363,7 @@ class TestClient(unittest.TestCase):
"$group_set": {},
"$lib": "posthog-python",
"$lib_version": VERSION,
"$geoip_disable": True,
},
)
self.assertTrue(isinstance(msg["timestamp"], str))
@@ -326,6 +385,7 @@ class TestClient(unittest.TestCase):
"$group_set": {"trait": "value"},
"$lib": "posthog-python",
"$lib_version": VERSION,
"$geoip_disable": True,
},
)
self.assertEqual(msg["timestamp"], "2014-09-03T00:00:00+00:00")
@@ -494,6 +554,74 @@ class TestClient(unittest.TestCase):
self.assertEqual(msg, "disabled")
def test_disable_geoip_default_on_events(self):
client = Client(FAKE_TEST_API_KEY, on_error=self.set_fail, disable_geoip=True)
_, capture_msg = client.capture("distinct_id", "python test event")
client.flush()
self.assertEqual(capture_msg["properties"]["$geoip_disable"], True)
_, identify_msg = client.identify("distinct_id", {"trait": "value"})
client.flush()
self.assertEqual(identify_msg["properties"]["$geoip_disable"], True)
def test_disable_geoip_override_on_events(self):
client = Client(FAKE_TEST_API_KEY, on_error=self.set_fail, disable_geoip=False)
_, capture_msg = client.set("distinct_id", {"a": "b", "c": "d"}, disable_geoip=True)
client.flush()
self.assertEqual(capture_msg["properties"]["$geoip_disable"], True)
_, identify_msg = client.page("distinct_id", "http://a.com", {"trait": "value"}, disable_geoip=False)
client.flush()
self.assertEqual("$geoip_disable" not in identify_msg["properties"], True)
def test_disable_geoip_method_overrides_init_on_events(self):
client = Client(FAKE_TEST_API_KEY, on_error=self.set_fail, disable_geoip=True)
_, msg = client.capture("distinct_id", "python test event", disable_geoip=False)
client.flush()
self.assertTrue("$geoip_disable" not in msg["properties"])
@mock.patch("posthog.client.decide")
def test_disable_geoip_default_on_decide(self, patch_decide):
patch_decide.return_value = {
"featureFlags": {"beta-feature": "random-variant", "alpha-feature": True, "off-feature": False}
}
client = Client(FAKE_TEST_API_KEY, on_error=self.set_fail, disable_geoip=False)
client.get_feature_flag("random_key", "some_id", disable_geoip=True)
patch_decide.assert_called_with(
"random_key",
None,
timeout=10,
distinct_id="some_id",
groups={},
person_properties={},
group_properties={},
disable_geoip=True,
)
patch_decide.reset_mock()
client.feature_enabled("random_key", "feature_enabled_distinct_id", disable_geoip=True)
patch_decide.assert_called_with(
"random_key",
None,
timeout=10,
distinct_id="feature_enabled_distinct_id",
groups={},
person_properties={},
group_properties={},
disable_geoip=True,
)
patch_decide.reset_mock()
client.get_all_flags_and_payloads("all_flags_payloads_id")
patch_decide.assert_called_with(
"random_key",
None,
timeout=10,
distinct_id="all_flags_payloads_id",
groups={},
person_properties={},
group_properties={},
disable_geoip=False,
)
@mock.patch("posthog.client.Poller")
@mock.patch("posthog.client.get")
def test_call_identify_fails(self, patch_get, patch_poll):
+42
View File
@@ -1890,6 +1890,7 @@ class TestCaptureCalls(unittest.TestCase):
"$feature_flag_called",
{"$feature_flag": "complex-flag", "$feature_flag_response": True, "locally_evaluated": True},
groups={},
disable_geoip=None,
)
patch_capture.reset_mock()
@@ -1914,6 +1915,7 @@ class TestCaptureCalls(unittest.TestCase):
"$feature_flag_called",
{"$feature_flag": "complex-flag", "$feature_flag_response": True, "locally_evaluated": True},
groups={},
disable_geoip=None,
)
patch_capture.reset_mock()
@@ -1946,6 +1948,45 @@ class TestCaptureCalls(unittest.TestCase):
"$feature_flag_called",
{"$feature_flag": "decide-flag", "$feature_flag_response": "decide-value", "locally_evaluated": False},
groups={"organization": "org1"},
disable_geoip=None,
)
@mock.patch.object(Client, "capture")
@mock.patch("posthog.client.decide")
def test_disable_geoip_get_flag_capture_call(self, patch_decide, patch_capture):
patch_decide.return_value = {"featureFlags": {"decide-flag": "decide-value"}}
client = Client(FAKE_TEST_API_KEY, personal_api_key=FAKE_TEST_API_KEY, disable_geoip=True)
client.feature_flags = [
{
"id": 1,
"name": "Beta Feature",
"key": "complex-flag",
"is_simple_flag": False,
"active": True,
"filters": {
"groups": [
{
"properties": [{"key": "region", "value": "USA"}],
"rollout_percentage": 100,
}
],
},
}
]
client.get_feature_flag(
"complex-flag",
"some-distinct-id",
person_properties={"region": "USA", "name": "Aloha"},
disable_geoip=False,
)
patch_capture.assert_called_with(
"some-distinct-id",
"$feature_flag_called",
{"$feature_flag": "complex-flag", "$feature_flag_response": True, "locally_evaluated": True},
groups={},
disable_geoip=False,
)
@mock.patch("posthog.client.MAX_DICT_SIZE", 100)
@@ -1979,6 +2020,7 @@ class TestCaptureCalls(unittest.TestCase):
"$feature_flag_called",
{"$feature_flag": "complex-flag", "$feature_flag_response": True, "locally_evaluated": True},
groups={},
disable_geoip=None,
)
self.assertEqual(len(client.distinct_ids_feature_flags_reported), i % 100 + 1)
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION = "2.5.0"
VERSION = "3.0.0"
if __name__ == "__main__":
print(VERSION, end="") # noqa: T201