From d4407ecbdb10f9b76b70291f1df08e7c53f68dce Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Wed, 29 Apr 2026 20:00:49 +0200 Subject: [PATCH] fix: address straightforward open issue bugs --- .sampo/changesets/quiet-otter-fixes.md | 5 +++++ posthog/__init__.py | 2 +- posthog/client.py | 18 ++++++++++++------ posthog/consumer.py | 1 + posthog/test/test_client.py | 10 +++++++++- posthog/test/test_consumer.py | 1 + posthog/test/test_feature_flags.py | 10 +++++----- posthog/test/test_module.py | 23 +++++++++++++++++++++++ 8 files changed, 57 insertions(+), 13 deletions(-) create mode 100644 .sampo/changesets/quiet-otter-fixes.md diff --git a/.sampo/changesets/quiet-otter-fixes.md b/.sampo/changesets/quiet-otter-fixes.md new file mode 100644 index 00000000..e94fdc1f --- /dev/null +++ b/.sampo/changesets/quiet-otter-fixes.md @@ -0,0 +1,5 @@ +--- +pypi/posthog: patch +--- + +Fix disabled no-op setup, oversized queue drops, and local feature flag auth errors. diff --git a/posthog/__init__.py b/posthog/__init__.py index b594c01a..dee95e79 100644 --- a/posthog/__init__.py +++ b/posthog/__init__.py @@ -857,7 +857,7 @@ def shutdown(): def setup() -> Client: global default_client if not default_client: - if not api_key: + if not api_key and not disabled: raise ValueError("API key is required") default_client = Client( api_key, diff --git a/posthog/client.py b/posthog/client.py index a4ffa1ed..ecaa7a29 100644 --- a/posthog/client.py +++ b/posthog/client.py @@ -166,7 +166,7 @@ class Client(object): def __init__( self, - project_api_key: str, + project_api_key: Optional[str], host=None, debug=False, max_queue_size=10000, @@ -220,7 +220,12 @@ def __init__( self.queue = queue.Queue(max_queue_size) # api_key: This should be the Team API Key (token), public - self.api_key = project_api_key.strip() + if project_api_key is None: + if not disabled: + raise ValueError("API key is required") + self.api_key = "" + else: + self.api_key = project_api_key.strip() self.on_error = on_error self.debug = debug @@ -290,7 +295,7 @@ def __init__( else: self.log.setLevel(logging.WARNING) - if not self.api_key: + if not self.api_key and not self.disabled: self.log.error( "api_key is empty after trimming whitespace; check your project API key" ) @@ -1351,7 +1356,8 @@ def _fetch_feature_flags_from_api(self): except APIError as e: if e.status == 401: self.log.error( - "[FEATURE FLAGS] Error loading feature flags: To use feature flags, please set a valid personal_api_key. More information: https://posthog.com/docs/api/overview" + "[FEATURE FLAGS] Error loading feature flags: %s. Please verify both your project_api_key and personal_api_key. More information: https://posthog.com/docs/api/overview", + e.message, ) self.feature_flags = [] self.group_type_mapping = {} @@ -1363,8 +1369,8 @@ def _fetch_feature_flags_from_api(self): if self.debug: raise APIError( status=401, - message="You are using a write-only key with feature flags. " - "To use feature flags, please set a personal_api_key " + message=f"Error loading feature flags: {e.message}. " + "Please verify both your project_api_key and personal_api_key. " "More information: https://posthog.com/docs/api/overview", ) elif e.status == 402: diff --git a/posthog/consumer.py b/posthog/consumer.py index d4ce068e..8f3fa3b5 100644 --- a/posthog/consumer.py +++ b/posthog/consumer.py @@ -112,6 +112,7 @@ def next(self): self.log.error( "Item exceeds 900kib limit, dropping. (%s)", str(item) ) + queue.task_done() continue items.append(item) total_size += item_size diff --git a/posthog/test/test_client.py b/posthog/test/test_client.py index 587e7005..5c7602bd 100644 --- a/posthog/test/test_client.py +++ b/posthog/test/test_client.py @@ -73,6 +73,12 @@ def test_trims_host_and_personal_api_key_whitespace(self): self.assertEqual(client.host, "https://eu.i.posthog.com") self.assertIsNone(client.personal_api_key) + def test_disabled_client_allows_missing_api_key(self): + client = Client(None, disabled=True, send=False) + + self.assertEqual(client.api_key, "") + self.assertIsNone(client.capture("event", distinct_id="distinct_id")) + def test_empty_flush(self): self.client.flush() @@ -522,7 +528,9 @@ def test_load_feature_flags_unauthorized(self, patch_get): self.assertEqual(client.feature_flags_by_key, {}) self.assertEqual(client.group_type_mapping, {}) self.assertEqual(client.cohorts, {}) - self.assertIn("please set a valid personal_api_key", logs.output[0]) + self.assertIn("Unauthorized", logs.output[0]) + self.assertIn("project_api_key", logs.output[0]) + self.assertIn("personal_api_key", logs.output[0]) @mock.patch("posthog.client.flags") def test_dont_override_capture_with_local_flags(self, patch_flags): diff --git a/posthog/test/test_consumer.py b/posthog/test/test_consumer.py index e032e813..f476b82a 100644 --- a/posthog/test/test_consumer.py +++ b/posthog/test/test_consumer.py @@ -45,6 +45,7 @@ def test_dropping_oversize_msg(self) -> None: next = consumer.next() self.assertEqual(next, []) self.assertTrue(q.empty()) + self.assertEqual(q.unfinished_tasks, 0) def test_upload(self) -> None: q = Queue() diff --git a/posthog/test/test_feature_flags.py b/posthog/test/test_feature_flags.py index 0ce5e72c..2170ce16 100644 --- a/posthog/test/test_feature_flags.py +++ b/posthog/test/test_feature_flags.py @@ -2546,12 +2546,12 @@ def test_load_feature_flags_wrong_key(self, patch_get, _patch_poll): with self.assertLogs("posthog", level="ERROR") as logs: client.load_feature_flags() - self.assertEqual( - logs.output[0], - "ERROR:posthog:[FEATURE FLAGS] Error loading feature flags: To use feature flags, please set a valid personal_api_key. More information: https://posthog.com/docs/api/overview", - ) + self.assertIn("Unauthorized", logs.output[0]) + self.assertIn("project_api_key", logs.output[0]) + self.assertIn("personal_api_key", logs.output[0]) client.debug = True - self.assertRaises(APIError, client.load_feature_flags) + with self.assertRaisesRegex(APIError, "Unauthorized"): + client.load_feature_flags() @mock.patch("posthog.client.flags") @mock.patch("posthog.client.get") diff --git a/posthog/test/test_module.py b/posthog/test/test_module.py index 03bce00b..21f35c83 100644 --- a/posthog/test/test_module.py +++ b/posthog/test/test_module.py @@ -36,6 +36,29 @@ def test_flush(self): self.posthog.flush() +class TestModuleLevelDisabledSetup(unittest.TestCase): + def setUp(self): + self._original_default_client = posthog.default_client + self._original_api_key = posthog.api_key + self._original_disabled = posthog.disabled + self._original_send = posthog.send + posthog.default_client = None + posthog.api_key = None + posthog.disabled = True + posthog.send = False + + def tearDown(self): + posthog.default_client = self._original_default_client + posthog.api_key = self._original_api_key + posthog.disabled = self._original_disabled + posthog.send = self._original_send + + def test_disabled_module_level_capture_allows_missing_api_key(self): + self.assertIsNone(posthog.capture("event", distinct_id="distinct_id")) + self.assertIsNotNone(posthog.default_client) + self.assertEqual(posthog.default_client.api_key, "") + + class TestModuleLevelWrappers(unittest.TestCase): """Test that module-level wrapper functions in posthog/__init__.py correctly propagate all parameters to the Client methods."""