Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .sampo/changesets/quiet-otter-fixes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
pypi/posthog: patch
---

Fix disabled no-op setup, oversized queue drops, and local feature flag auth errors.
2 changes: 1 addition & 1 deletion posthog/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
18 changes: 12 additions & 6 deletions posthog/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"
)
Expand Down Expand Up @@ -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 = {}
Expand All @@ -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:
Expand Down
1 change: 1 addition & 0 deletions posthog/consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 9 additions & 1 deletion posthog/test/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -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):
Expand Down
1 change: 1 addition & 0 deletions posthog/test/test_consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
10 changes: 5 additions & 5 deletions posthog/test/test_feature_flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
23 changes: 23 additions & 0 deletions posthog/test/test_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down
Loading