From ca6ba0ebfc7cd4c02d2959ffde1ebc3443dcbee6 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Thu, 28 May 2026 12:28:06 +0200 Subject: [PATCH 1/3] fix: no-op global client for blank api key --- posthog/__init__.py | 12 +++++------- posthog/test/test_module.py | 23 +++++++++++++++++------ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/posthog/__init__.py b/posthog/__init__.py index 93fead78..b370feba 100644 --- a/posthog/__init__.py +++ b/posthog/__init__.py @@ -266,8 +266,8 @@ def get_tags() -> Dict[str, Any]: the corresponding constructor arguments. Attributes: - api_key: Project API key/token used by the global client. Required before - calling any global capture or feature flag API. + api_key: Project API key/token used by the global client. Missing or blank + values create a disabled no-op global client. host: PostHog ingestion host. Defaults to the US ingestion endpoint when not set. on_error: Optional callback invoked by background consumers when event upload @@ -1066,18 +1066,16 @@ def setup() -> Client: Returns: The global ``Client`` instance. - Raises: - ValueError: If ``api_key`` has not been configured. + If ``api_key`` is missing or blank, the returned client is disabled and + module-level calls become no-ops. Category: Initialization """ global default_client if not default_client: - if not api_key: - raise ValueError("API key is required") default_client = Client( - api_key, + api_key or "", host=host, debug=debug, on_error=on_error, diff --git a/posthog/test/test_module.py b/posthog/test/test_module.py index aa87314f..b9dea8c5 100644 --- a/posthog/test/test_module.py +++ b/posthog/test/test_module.py @@ -43,7 +43,6 @@ def setUp(self): self._original_disabled = posthog.disabled self._original_send = posthog.send posthog.default_client = None - posthog.api_key = " \n\t " posthog.disabled = False posthog.send = False @@ -53,12 +52,24 @@ def tearDown(self): posthog.disabled = self._original_disabled posthog.send = self._original_send - def test_setup_preserves_client_disabled_when_trimmed_api_key_is_empty(self): - posthog.setup() + @parameterized.expand( + [ + ("unset", None), + ("empty", ""), + ("whitespace", " \n\t "), + ] + ) + def test_setup_configures_disabled_client_when_api_key_is_blank( + self, _name, api_key + ): + posthog.api_key = api_key + + client = posthog.setup() - self.assertIsNotNone(posthog.default_client) - self.assertEqual(posthog.default_client.api_key, "") - self.assertTrue(posthog.default_client.disabled) + self.assertIs(client, posthog.default_client) + self.assertEqual(client.api_key, "") + self.assertTrue(client.disabled) + self.assertIsNone(posthog.capture("Module Python Event", distinct_id="john")) class TestModuleLevelWrappers(unittest.TestCase): From cbafc3641db53e7fac4163c66995aa3c183fc41c Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Thu, 28 May 2026 12:30:28 +0200 Subject: [PATCH 2/3] chore: add changeset for blank api key no-op --- .sampo/changesets/haughty-thunderbearer-mielikki.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .sampo/changesets/haughty-thunderbearer-mielikki.md diff --git a/.sampo/changesets/haughty-thunderbearer-mielikki.md b/.sampo/changesets/haughty-thunderbearer-mielikki.md new file mode 100644 index 00000000..68cc9bc6 --- /dev/null +++ b/.sampo/changesets/haughty-thunderbearer-mielikki.md @@ -0,0 +1,5 @@ +--- +pypi/posthog: patch +--- + +Make module-level setup no-op when API key is blank From 3bd7eaa5bfed1b4e45622a5361fea02255bf32c3 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Thu, 28 May 2026 15:55:59 +0200 Subject: [PATCH 3/3] fix: normalize module api key before setup --- posthog/__init__.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/posthog/__init__.py b/posthog/__init__.py index b370feba..559aba88 100644 --- a/posthog/__init__.py +++ b/posthog/__init__.py @@ -1064,18 +1064,17 @@ def setup() -> Client: ``setup()`` is called automatically by global APIs such as ``capture()``. Returns: - The global ``Client`` instance. - - If ``api_key`` is missing or blank, the returned client is disabled and - module-level calls become no-ops. + The global ``Client`` instance. If ``api_key`` is missing or blank, + the client is disabled and module-level calls become no-ops. Category: Initialization """ global default_client if not default_client: + configured_api_key = api_key.strip() if api_key else "" default_client = Client( - api_key or "", + configured_api_key, host=host, debug=debug, on_error=on_error,