diff --git a/README.md b/README.md index 22f43ee..a8f39a1 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,8 @@ [![PyPI](https://img.shields.io/pypi/v/posthog)](https://pypi.org/project/posthog/) -Please see the main [PostHog docs](https://posthog.com/docs). -Specifically, the [Python integration](https://posthog.com/docs/integrations/python-integration) details. +Please see the [Python integration docs](https://posthog.com/docs/integrations/python-integration) for details. ## Development @@ -14,6 +13,7 @@ Specifically, the [Python integration](https://posthog.com/docs/integrations/pyt 2. Run `source env/bin/activate` (activates the virtual environment) 3. Run `python3 -m pip install -e ".[test]"` (installs the package in develop mode, along with test dependencies) 4. Run `make test` + 1. To run a specific test do `pytest -k test_no_api_key` ### Running Locally diff --git a/posthog/client.py b/posthog/client.py index fe68fd6..7d85cd4 100644 --- a/posthog/client.py +++ b/posthog/client.py @@ -354,39 +354,36 @@ def feature_enabled(self, key, distinct_id, default=False, *, groups={}): require("distinct_id", distinct_id, ID_TYPES) require("groups", groups, dict) - if not self.personal_api_key: - self.log.warning("[FEATURE FLAGS] You have to specify a personal_api_key to use feature flags.") - if not self.feature_flags: + if self.feature_flags == None and self.personal_api_key: self.load_feature_flags() + response = None # If loading in previous line failed - if not self.feature_flags: - response = default - else: + if self.feature_flags: for flag in self.feature_flags: if flag["key"] == key: feature_flag = flag - break - else: - return default - - if feature_flag.get("is_simple_flag"): - response = _hash(key, distinct_id) <= ((feature_flag.get("rollout_percentage", 100) or 100) / 100) + if feature_flag.get("is_simple_flag"): + response = _hash(key, distinct_id) <= (feature_flag.get("rollout_percentage", 100) / 100) + if response == None: + try: + request_data = { + "distinct_id": distinct_id, + "personal_api_key": self.personal_api_key, + "groups": groups, + } + resp_data = decide(self.api_key, self.host, timeout=10, **request_data) + except Exception as e: + response = default + self.log.warning( + "[FEATURE FLAGS] Unable to get data for flag %s, because of the following error:" % key + ) + self.log.warning(e) else: - try: - request_data = { - "distinct_id": distinct_id, - "personal_api_key": self.personal_api_key, - "groups": groups, - } - resp_data = decide(self.api_key, self.host, timeout=10, **request_data) - response = key in resp_data["featureFlags"] - except Exception as e: - response = default - self.log.warning( - "[FEATURE FLAGS] Unable to get data for flag %s, because of the following error:" % key - ) - self.log.warning(e) + if key in resp_data["featureFlags"]: + return True + else: + return default self.capture(distinct_id, "$feature_flag_called", {"$feature_flag": key, "$feature_flag_response": response}) return response diff --git a/posthog/test/test_client.py b/posthog/test/test_client.py index 127d161..3cdf0f9 100644 --- a/posthog/test/test_client.py +++ b/posthog/test/test_client.py @@ -404,13 +404,25 @@ def test_load_feature_flags_wrong_key(self): with freeze_time("2020-01-01T12:01:00.0000Z"): self.assertRaises(APIError, client.load_feature_flags) + @mock.patch("posthog.client.decide") @mock.patch("posthog.client.get") - def test_feature_enabled_simple(self, patch_get): + def test_feature_enabled_simple(self, patch_get, patch_decide): client = Client(TEST_API_KEY) client.feature_flags = [ {"id": 1, "name": "Beta Feature", "key": "beta-feature", "is_simple_flag": True, "rollout_percentage": 100} ] self.assertTrue(client.feature_enabled("beta-feature", "distinct_id")) + self.assertEqual(patch_decide.call_count, 0) + + @mock.patch("posthog.client.decide") + @mock.patch("posthog.client.get") + def test_feature_enabled_simple_is_false(self, patch_get, patch_decide): + client = Client(TEST_API_KEY) + client.feature_flags = [ + {"id": 1, "name": "Beta Feature", "key": "beta-feature", "is_simple_flag": True, "rollout_percentage": 0} + ] + self.assertFalse(client.feature_enabled("beta-feature", "distinct_id")) + self.assertEqual(patch_decide.call_count, 0) @mock.patch("posthog.client.get") def test_feature_enabled_simple_with_project_api_key(self, patch_get): @@ -444,8 +456,9 @@ def test_feature_enabled_simple_with_none_rollout_percentage(self, patch_get): self.assertTrue(client.feature_enabled("beta-feature", "distinct_id")) @mock.patch("posthog.client.Poller") - @mock.patch("posthog.client.get") - def test_feature_enabled_doesnt_exist(self, patch_get, patch_poll): + @mock.patch("posthog.client.decide") + def test_feature_enabled_doesnt_exist(self, patch_decide, patch_poll): + patch_decide.return_value = {"featureFlags": []} client = Client(TEST_API_KEY, personal_api_key="test") client.feature_flags = [] @@ -453,13 +466,14 @@ def test_feature_enabled_doesnt_exist(self, patch_get, patch_poll): self.assertTrue(client.feature_enabled("doesnt-exist", "distinct_id", True)) @mock.patch("posthog.client.Poller") - @mock.patch("posthog.client.get") - def test_personal_api_key_doesnt_exist(self, patch_get, patch_poll): + @mock.patch("posthog.client.decide") + def test_personal_api_key_doesnt_exist(self, patch_decide, patch_poll): client = Client(TEST_API_KEY) client.feature_flags = [] - self.assertFalse(client.feature_enabled("doesnt-exist", "distinct_id")) - self.assertTrue(client.feature_enabled("doesnt-exist", "distinct_id", True)) + patch_decide.return_value = {"featureFlags": ["feature-flag"]} + + self.assertTrue(client.feature_enabled("feature-flag", "distinct_id")) @mock.patch("posthog.client.Poller") @mock.patch("posthog.client.get")