posthog 7.4.0__py3-none-any.whl → 7.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- posthog/ai/openai/openai.py +27 -2
- posthog/ai/openai/openai_async.py +27 -2
- posthog/ai/utils.py +2 -2
- posthog/client.py +11 -11
- posthog/test/test_client.py +86 -1
- posthog/test/test_feature_flags.py +9 -55
- posthog/version.py +1 -1
- {posthog-7.4.0.dist-info → posthog-7.4.1.dist-info}/METADATA +1 -1
- {posthog-7.4.0.dist-info → posthog-7.4.1.dist-info}/RECORD +12 -12
- {posthog-7.4.0.dist-info → posthog-7.4.1.dist-info}/WHEEL +0 -0
- {posthog-7.4.0.dist-info → posthog-7.4.1.dist-info}/licenses/LICENSE +0 -0
- {posthog-7.4.0.dist-info → posthog-7.4.1.dist-info}/top_level.txt +0 -0
posthog/ai/openai/openai.py
CHANGED
|
@@ -124,14 +124,23 @@ class WrappedResponses:
|
|
|
124
124
|
start_time = time.time()
|
|
125
125
|
usage_stats: TokenUsage = TokenUsage()
|
|
126
126
|
final_content = []
|
|
127
|
+
model_from_response: Optional[str] = None
|
|
127
128
|
response = self._original.create(**kwargs)
|
|
128
129
|
|
|
129
130
|
def generator():
|
|
130
131
|
nonlocal usage_stats
|
|
131
132
|
nonlocal final_content # noqa: F824
|
|
133
|
+
nonlocal model_from_response
|
|
132
134
|
|
|
133
135
|
try:
|
|
134
136
|
for chunk in response:
|
|
137
|
+
# Extract model from response object in chunk (for stored prompts)
|
|
138
|
+
if hasattr(chunk, "response") and chunk.response:
|
|
139
|
+
if model_from_response is None and hasattr(
|
|
140
|
+
chunk.response, "model"
|
|
141
|
+
):
|
|
142
|
+
model_from_response = chunk.response.model
|
|
143
|
+
|
|
135
144
|
# Extract usage stats from chunk
|
|
136
145
|
chunk_usage = extract_openai_usage_from_chunk(chunk, "responses")
|
|
137
146
|
|
|
@@ -161,6 +170,7 @@ class WrappedResponses:
|
|
|
161
170
|
latency,
|
|
162
171
|
output,
|
|
163
172
|
None, # Responses API doesn't have tools
|
|
173
|
+
model_from_response,
|
|
164
174
|
)
|
|
165
175
|
|
|
166
176
|
return generator()
|
|
@@ -177,6 +187,7 @@ class WrappedResponses:
|
|
|
177
187
|
latency: float,
|
|
178
188
|
output: Any,
|
|
179
189
|
available_tool_calls: Optional[List[Dict[str, Any]]] = None,
|
|
190
|
+
model_from_response: Optional[str] = None,
|
|
180
191
|
):
|
|
181
192
|
from posthog.ai.types import StreamingEventData
|
|
182
193
|
from posthog.ai.openai.openai_converter import (
|
|
@@ -189,9 +200,12 @@ class WrappedResponses:
|
|
|
189
200
|
formatted_input = format_openai_streaming_input(kwargs, "responses")
|
|
190
201
|
sanitized_input = sanitize_openai_response(formatted_input)
|
|
191
202
|
|
|
203
|
+
# Use model from kwargs, fallback to model from response
|
|
204
|
+
model = kwargs.get("model") or model_from_response or "unknown"
|
|
205
|
+
|
|
192
206
|
event_data = StreamingEventData(
|
|
193
207
|
provider="openai",
|
|
194
|
-
model=
|
|
208
|
+
model=model,
|
|
195
209
|
base_url=str(self._client.base_url),
|
|
196
210
|
kwargs=kwargs,
|
|
197
211
|
formatted_input=sanitized_input,
|
|
@@ -320,6 +334,7 @@ class WrappedCompletions:
|
|
|
320
334
|
usage_stats: TokenUsage = TokenUsage()
|
|
321
335
|
accumulated_content = []
|
|
322
336
|
accumulated_tool_calls: Dict[int, Dict[str, Any]] = {}
|
|
337
|
+
model_from_response: Optional[str] = None
|
|
323
338
|
if "stream_options" not in kwargs:
|
|
324
339
|
kwargs["stream_options"] = {}
|
|
325
340
|
kwargs["stream_options"]["include_usage"] = True
|
|
@@ -329,9 +344,14 @@ class WrappedCompletions:
|
|
|
329
344
|
nonlocal usage_stats
|
|
330
345
|
nonlocal accumulated_content # noqa: F824
|
|
331
346
|
nonlocal accumulated_tool_calls
|
|
347
|
+
nonlocal model_from_response
|
|
332
348
|
|
|
333
349
|
try:
|
|
334
350
|
for chunk in response:
|
|
351
|
+
# Extract model from chunk (Chat Completions chunks have model field)
|
|
352
|
+
if model_from_response is None and hasattr(chunk, "model"):
|
|
353
|
+
model_from_response = chunk.model
|
|
354
|
+
|
|
335
355
|
# Extract usage stats from chunk
|
|
336
356
|
chunk_usage = extract_openai_usage_from_chunk(chunk, "chat")
|
|
337
357
|
|
|
@@ -376,6 +396,7 @@ class WrappedCompletions:
|
|
|
376
396
|
accumulated_content,
|
|
377
397
|
tool_calls_list,
|
|
378
398
|
extract_available_tool_calls("openai", kwargs),
|
|
399
|
+
model_from_response,
|
|
379
400
|
)
|
|
380
401
|
|
|
381
402
|
return generator()
|
|
@@ -393,6 +414,7 @@ class WrappedCompletions:
|
|
|
393
414
|
output: Any,
|
|
394
415
|
tool_calls: Optional[List[Dict[str, Any]]] = None,
|
|
395
416
|
available_tool_calls: Optional[List[Dict[str, Any]]] = None,
|
|
417
|
+
model_from_response: Optional[str] = None,
|
|
396
418
|
):
|
|
397
419
|
from posthog.ai.types import StreamingEventData
|
|
398
420
|
from posthog.ai.openai.openai_converter import (
|
|
@@ -405,9 +427,12 @@ class WrappedCompletions:
|
|
|
405
427
|
formatted_input = format_openai_streaming_input(kwargs, "chat")
|
|
406
428
|
sanitized_input = sanitize_openai(formatted_input)
|
|
407
429
|
|
|
430
|
+
# Use model from kwargs, fallback to model from response
|
|
431
|
+
model = kwargs.get("model") or model_from_response or "unknown"
|
|
432
|
+
|
|
408
433
|
event_data = StreamingEventData(
|
|
409
434
|
provider="openai",
|
|
410
|
-
model=
|
|
435
|
+
model=model,
|
|
411
436
|
base_url=str(self._client.base_url),
|
|
412
437
|
kwargs=kwargs,
|
|
413
438
|
formatted_input=sanitized_input,
|
|
@@ -128,14 +128,23 @@ class WrappedResponses:
|
|
|
128
128
|
start_time = time.time()
|
|
129
129
|
usage_stats: TokenUsage = TokenUsage()
|
|
130
130
|
final_content = []
|
|
131
|
+
model_from_response: Optional[str] = None
|
|
131
132
|
response = await self._original.create(**kwargs)
|
|
132
133
|
|
|
133
134
|
async def async_generator():
|
|
134
135
|
nonlocal usage_stats
|
|
135
136
|
nonlocal final_content # noqa: F824
|
|
137
|
+
nonlocal model_from_response
|
|
136
138
|
|
|
137
139
|
try:
|
|
138
140
|
async for chunk in response:
|
|
141
|
+
# Extract model from response object in chunk (for stored prompts)
|
|
142
|
+
if hasattr(chunk, "response") and chunk.response:
|
|
143
|
+
if model_from_response is None and hasattr(
|
|
144
|
+
chunk.response, "model"
|
|
145
|
+
):
|
|
146
|
+
model_from_response = chunk.response.model
|
|
147
|
+
|
|
139
148
|
# Extract usage stats from chunk
|
|
140
149
|
chunk_usage = extract_openai_usage_from_chunk(chunk, "responses")
|
|
141
150
|
|
|
@@ -166,6 +175,7 @@ class WrappedResponses:
|
|
|
166
175
|
latency,
|
|
167
176
|
output,
|
|
168
177
|
extract_available_tool_calls("openai", kwargs),
|
|
178
|
+
model_from_response,
|
|
169
179
|
)
|
|
170
180
|
|
|
171
181
|
return async_generator()
|
|
@@ -182,13 +192,17 @@ class WrappedResponses:
|
|
|
182
192
|
latency: float,
|
|
183
193
|
output: Any,
|
|
184
194
|
available_tool_calls: Optional[List[Dict[str, Any]]] = None,
|
|
195
|
+
model_from_response: Optional[str] = None,
|
|
185
196
|
):
|
|
186
197
|
if posthog_trace_id is None:
|
|
187
198
|
posthog_trace_id = str(uuid.uuid4())
|
|
188
199
|
|
|
200
|
+
# Use model from kwargs, fallback to model from response
|
|
201
|
+
model = kwargs.get("model") or model_from_response or "unknown"
|
|
202
|
+
|
|
189
203
|
event_properties = {
|
|
190
204
|
"$ai_provider": "openai",
|
|
191
|
-
"$ai_model":
|
|
205
|
+
"$ai_model": model,
|
|
192
206
|
"$ai_model_parameters": get_model_params(kwargs),
|
|
193
207
|
"$ai_input": with_privacy_mode(
|
|
194
208
|
self._client._ph_client,
|
|
@@ -350,6 +364,7 @@ class WrappedCompletions:
|
|
|
350
364
|
usage_stats: TokenUsage = TokenUsage()
|
|
351
365
|
accumulated_content = []
|
|
352
366
|
accumulated_tool_calls: Dict[int, Dict[str, Any]] = {}
|
|
367
|
+
model_from_response: Optional[str] = None
|
|
353
368
|
|
|
354
369
|
if "stream_options" not in kwargs:
|
|
355
370
|
kwargs["stream_options"] = {}
|
|
@@ -360,9 +375,14 @@ class WrappedCompletions:
|
|
|
360
375
|
nonlocal usage_stats
|
|
361
376
|
nonlocal accumulated_content # noqa: F824
|
|
362
377
|
nonlocal accumulated_tool_calls
|
|
378
|
+
nonlocal model_from_response
|
|
363
379
|
|
|
364
380
|
try:
|
|
365
381
|
async for chunk in response:
|
|
382
|
+
# Extract model from chunk (Chat Completions chunks have model field)
|
|
383
|
+
if model_from_response is None and hasattr(chunk, "model"):
|
|
384
|
+
model_from_response = chunk.model
|
|
385
|
+
|
|
366
386
|
# Extract usage stats from chunk
|
|
367
387
|
chunk_usage = extract_openai_usage_from_chunk(chunk, "chat")
|
|
368
388
|
if chunk_usage:
|
|
@@ -405,6 +425,7 @@ class WrappedCompletions:
|
|
|
405
425
|
accumulated_content,
|
|
406
426
|
tool_calls_list,
|
|
407
427
|
extract_available_tool_calls("openai", kwargs),
|
|
428
|
+
model_from_response,
|
|
408
429
|
)
|
|
409
430
|
|
|
410
431
|
return async_generator()
|
|
@@ -422,13 +443,17 @@ class WrappedCompletions:
|
|
|
422
443
|
output: Any,
|
|
423
444
|
tool_calls: Optional[List[Dict[str, Any]]] = None,
|
|
424
445
|
available_tool_calls: Optional[List[Dict[str, Any]]] = None,
|
|
446
|
+
model_from_response: Optional[str] = None,
|
|
425
447
|
):
|
|
426
448
|
if posthog_trace_id is None:
|
|
427
449
|
posthog_trace_id = str(uuid.uuid4())
|
|
428
450
|
|
|
451
|
+
# Use model from kwargs, fallback to model from response
|
|
452
|
+
model = kwargs.get("model") or model_from_response or "unknown"
|
|
453
|
+
|
|
429
454
|
event_properties = {
|
|
430
455
|
"$ai_provider": "openai",
|
|
431
|
-
"$ai_model":
|
|
456
|
+
"$ai_model": model,
|
|
432
457
|
"$ai_model_parameters": get_model_params(kwargs),
|
|
433
458
|
"$ai_input": with_privacy_mode(
|
|
434
459
|
self._client._ph_client,
|
posthog/ai/utils.py
CHANGED
|
@@ -285,7 +285,7 @@ def call_llm_and_track_usage(
|
|
|
285
285
|
|
|
286
286
|
event_properties = {
|
|
287
287
|
"$ai_provider": provider,
|
|
288
|
-
"$ai_model": kwargs.get("model"),
|
|
288
|
+
"$ai_model": kwargs.get("model") or getattr(response, "model", None),
|
|
289
289
|
"$ai_model_parameters": get_model_params(kwargs),
|
|
290
290
|
"$ai_input": with_privacy_mode(
|
|
291
291
|
ph_client, posthog_privacy_mode, sanitized_messages
|
|
@@ -396,7 +396,7 @@ async def call_llm_and_track_usage_async(
|
|
|
396
396
|
|
|
397
397
|
event_properties = {
|
|
398
398
|
"$ai_provider": provider,
|
|
399
|
-
"$ai_model": kwargs.get("model"),
|
|
399
|
+
"$ai_model": kwargs.get("model") or getattr(response, "model", None),
|
|
400
400
|
"$ai_model_parameters": get_model_params(kwargs),
|
|
401
401
|
"$ai_input": with_privacy_mode(
|
|
402
402
|
ph_client, posthog_privacy_mode, sanitized_messages
|
posthog/client.py
CHANGED
|
@@ -2,6 +2,7 @@ import atexit
|
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
4
|
import sys
|
|
5
|
+
import warnings
|
|
5
6
|
from datetime import datetime, timedelta
|
|
6
7
|
from typing import Any, Dict, Optional, Union
|
|
7
8
|
from typing_extensions import Unpack
|
|
@@ -679,15 +680,6 @@ class Client(object):
|
|
|
679
680
|
f"[FEATURE FLAGS] Unable to get feature variants: {e}"
|
|
680
681
|
)
|
|
681
682
|
|
|
682
|
-
elif self.feature_flags and event != "$feature_flag_called":
|
|
683
|
-
# Local evaluation is enabled, flags are loaded, so try and get all flags we can without going to the server
|
|
684
|
-
feature_variants = self.get_all_flags(
|
|
685
|
-
distinct_id,
|
|
686
|
-
groups=(groups or {}),
|
|
687
|
-
disable_geoip=disable_geoip,
|
|
688
|
-
only_evaluate_locally=True,
|
|
689
|
-
)
|
|
690
|
-
|
|
691
683
|
for feature, variant in (feature_variants or {}).items():
|
|
692
684
|
extra_properties[f"$feature/{feature}"] = variant
|
|
693
685
|
|
|
@@ -1797,7 +1789,7 @@ class Client(object):
|
|
|
1797
1789
|
person_properties=None,
|
|
1798
1790
|
group_properties=None,
|
|
1799
1791
|
only_evaluate_locally=False,
|
|
1800
|
-
send_feature_flag_events=
|
|
1792
|
+
send_feature_flag_events=False,
|
|
1801
1793
|
disable_geoip=None,
|
|
1802
1794
|
):
|
|
1803
1795
|
"""
|
|
@@ -1811,7 +1803,7 @@ class Client(object):
|
|
|
1811
1803
|
person_properties: A dictionary of person properties.
|
|
1812
1804
|
group_properties: A dictionary of group properties.
|
|
1813
1805
|
only_evaluate_locally: Whether to only evaluate locally.
|
|
1814
|
-
send_feature_flag_events:
|
|
1806
|
+
send_feature_flag_events: Deprecated. Use get_feature_flag() instead if you need events.
|
|
1815
1807
|
disable_geoip: Whether to disable GeoIP for this request.
|
|
1816
1808
|
|
|
1817
1809
|
Examples:
|
|
@@ -1827,6 +1819,14 @@ class Client(object):
|
|
|
1827
1819
|
Category:
|
|
1828
1820
|
Feature flags
|
|
1829
1821
|
"""
|
|
1822
|
+
if send_feature_flag_events:
|
|
1823
|
+
warnings.warn(
|
|
1824
|
+
"send_feature_flag_events is deprecated in get_feature_flag_payload() and will be removed "
|
|
1825
|
+
"in a future version. Use get_feature_flag() if you want to send $feature_flag_called events.",
|
|
1826
|
+
DeprecationWarning,
|
|
1827
|
+
stacklevel=2,
|
|
1828
|
+
)
|
|
1829
|
+
|
|
1830
1830
|
feature_flag_result = self._get_feature_flag_result(
|
|
1831
1831
|
key,
|
|
1832
1832
|
distinct_id,
|
posthog/test/test_client.py
CHANGED
|
@@ -409,7 +409,9 @@ class TestClient(unittest.TestCase):
|
|
|
409
409
|
)
|
|
410
410
|
client.feature_flags = [multivariate_flag, basic_flag, false_flag]
|
|
411
411
|
|
|
412
|
-
msg_uuid = client.capture(
|
|
412
|
+
msg_uuid = client.capture(
|
|
413
|
+
"python test event", distinct_id="distinct_id", send_feature_flags=True
|
|
414
|
+
)
|
|
413
415
|
self.assertIsNotNone(msg_uuid)
|
|
414
416
|
self.assertFalse(self.failed)
|
|
415
417
|
|
|
@@ -565,6 +567,7 @@ class TestClient(unittest.TestCase):
|
|
|
565
567
|
"python test event",
|
|
566
568
|
distinct_id="distinct_id",
|
|
567
569
|
properties={"$feature/beta-feature-local": "my-custom-variant"},
|
|
570
|
+
send_feature_flags=True,
|
|
568
571
|
)
|
|
569
572
|
self.assertIsNotNone(msg_uuid)
|
|
570
573
|
self.assertFalse(self.failed)
|
|
@@ -746,6 +749,88 @@ class TestClient(unittest.TestCase):
|
|
|
746
749
|
|
|
747
750
|
self.assertEqual(patch_flags.call_count, 0)
|
|
748
751
|
|
|
752
|
+
@mock.patch("posthog.client.flags")
|
|
753
|
+
def test_capture_with_send_feature_flags_false_and_local_evaluation_doesnt_send_flags(
|
|
754
|
+
self, patch_flags
|
|
755
|
+
):
|
|
756
|
+
"""Test that send_feature_flags=False with local evaluation enabled does NOT send flags"""
|
|
757
|
+
patch_flags.return_value = {"featureFlags": {"beta-feature": "remote-variant"}}
|
|
758
|
+
|
|
759
|
+
multivariate_flag = {
|
|
760
|
+
"id": 1,
|
|
761
|
+
"name": "Beta Feature",
|
|
762
|
+
"key": "beta-feature-local",
|
|
763
|
+
"active": True,
|
|
764
|
+
"rollout_percentage": 100,
|
|
765
|
+
"filters": {
|
|
766
|
+
"groups": [
|
|
767
|
+
{
|
|
768
|
+
"rollout_percentage": 100,
|
|
769
|
+
},
|
|
770
|
+
],
|
|
771
|
+
"multivariate": {
|
|
772
|
+
"variants": [
|
|
773
|
+
{
|
|
774
|
+
"key": "first-variant",
|
|
775
|
+
"name": "First Variant",
|
|
776
|
+
"rollout_percentage": 50,
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
"key": "second-variant",
|
|
780
|
+
"name": "Second Variant",
|
|
781
|
+
"rollout_percentage": 50,
|
|
782
|
+
},
|
|
783
|
+
]
|
|
784
|
+
},
|
|
785
|
+
},
|
|
786
|
+
}
|
|
787
|
+
simple_flag = {
|
|
788
|
+
"id": 2,
|
|
789
|
+
"name": "Simple Flag",
|
|
790
|
+
"key": "simple-flag",
|
|
791
|
+
"active": True,
|
|
792
|
+
"filters": {
|
|
793
|
+
"groups": [
|
|
794
|
+
{
|
|
795
|
+
"rollout_percentage": 100,
|
|
796
|
+
}
|
|
797
|
+
],
|
|
798
|
+
},
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
with mock.patch("posthog.client.batch_post") as mock_post:
|
|
802
|
+
client = Client(
|
|
803
|
+
FAKE_TEST_API_KEY,
|
|
804
|
+
on_error=self.set_fail,
|
|
805
|
+
personal_api_key=FAKE_TEST_API_KEY,
|
|
806
|
+
sync_mode=True,
|
|
807
|
+
)
|
|
808
|
+
client.feature_flags = [multivariate_flag, simple_flag]
|
|
809
|
+
|
|
810
|
+
msg_uuid = client.capture(
|
|
811
|
+
"python test event",
|
|
812
|
+
distinct_id="distinct_id",
|
|
813
|
+
send_feature_flags=False,
|
|
814
|
+
)
|
|
815
|
+
self.assertIsNotNone(msg_uuid)
|
|
816
|
+
self.assertFalse(self.failed)
|
|
817
|
+
|
|
818
|
+
# Get the enqueued message from the mock
|
|
819
|
+
mock_post.assert_called_once()
|
|
820
|
+
batch_data = mock_post.call_args[1]["batch"]
|
|
821
|
+
msg = batch_data[0]
|
|
822
|
+
|
|
823
|
+
self.assertEqual(msg["event"], "python test event")
|
|
824
|
+
self.assertEqual(msg["distinct_id"], "distinct_id")
|
|
825
|
+
|
|
826
|
+
# CRITICAL: Verify local flags are NOT included in the event
|
|
827
|
+
self.assertNotIn("$feature/beta-feature-local", msg["properties"])
|
|
828
|
+
self.assertNotIn("$feature/simple-flag", msg["properties"])
|
|
829
|
+
self.assertNotIn("$active_feature_flags", msg["properties"])
|
|
830
|
+
|
|
831
|
+
# CRITICAL: Verify the /flags API was NOT called
|
|
832
|
+
self.assertEqual(patch_flags.call_count, 0)
|
|
833
|
+
|
|
749
834
|
@mock.patch("posthog.client.flags")
|
|
750
835
|
def test_capture_with_send_feature_flags_true_and_local_evaluation_uses_local_flags(
|
|
751
836
|
self, patch_flags
|
|
@@ -3062,6 +3062,7 @@ class TestLocalEvaluation(unittest.TestCase):
|
|
|
3062
3062
|
"some-distinct-id",
|
|
3063
3063
|
match_value=True,
|
|
3064
3064
|
person_properties={"region": "USA"},
|
|
3065
|
+
send_feature_flag_events=True,
|
|
3065
3066
|
),
|
|
3066
3067
|
300,
|
|
3067
3068
|
)
|
|
@@ -4051,7 +4052,9 @@ class TestCaptureCalls(unittest.TestCase):
|
|
|
4051
4052
|
|
|
4052
4053
|
self.assertEqual(
|
|
4053
4054
|
client.get_feature_flag_payload(
|
|
4054
|
-
"decide-flag-with-payload",
|
|
4055
|
+
"decide-flag-with-payload",
|
|
4056
|
+
"some-distinct-id",
|
|
4057
|
+
send_feature_flag_events=True,
|
|
4055
4058
|
),
|
|
4056
4059
|
{"foo": "bar"},
|
|
4057
4060
|
)
|
|
@@ -4127,9 +4130,10 @@ class TestCaptureCalls(unittest.TestCase):
|
|
|
4127
4130
|
|
|
4128
4131
|
@mock.patch.object(Client, "capture")
|
|
4129
4132
|
@mock.patch("posthog.client.flags")
|
|
4130
|
-
def
|
|
4133
|
+
def test_get_feature_flag_payload_does_not_send_feature_flag_called_events(
|
|
4131
4134
|
self, patch_flags, patch_capture
|
|
4132
4135
|
):
|
|
4136
|
+
"""Test that get_feature_flag_payload does NOT send $feature_flag_called events"""
|
|
4133
4137
|
patch_flags.return_value = {
|
|
4134
4138
|
"featureFlags": {"person-flag": True},
|
|
4135
4139
|
"featureFlagPayloads": {"person-flag": 300},
|
|
@@ -4151,68 +4155,18 @@ class TestCaptureCalls(unittest.TestCase):
|
|
|
4151
4155
|
"rollout_percentage": 100,
|
|
4152
4156
|
}
|
|
4153
4157
|
],
|
|
4158
|
+
"payloads": {"true": '"payload"'},
|
|
4154
4159
|
},
|
|
4155
4160
|
}
|
|
4156
4161
|
]
|
|
4157
4162
|
|
|
4158
|
-
|
|
4159
|
-
client.get_feature_flag_payload(
|
|
4160
|
-
key="person-flag",
|
|
4161
|
-
distinct_id="some-distinct-id",
|
|
4162
|
-
person_properties={"region": "USA", "name": "Aloha"},
|
|
4163
|
-
)
|
|
4164
|
-
|
|
4165
|
-
# Assert that capture was called once, with the correct parameters
|
|
4166
|
-
self.assertEqual(patch_capture.call_count, 1)
|
|
4167
|
-
patch_capture.assert_called_with(
|
|
4168
|
-
"$feature_flag_called",
|
|
4169
|
-
distinct_id="some-distinct-id",
|
|
4170
|
-
properties={
|
|
4171
|
-
"$feature_flag": "person-flag",
|
|
4172
|
-
"$feature_flag_response": True,
|
|
4173
|
-
"locally_evaluated": True,
|
|
4174
|
-
"$feature/person-flag": True,
|
|
4175
|
-
},
|
|
4176
|
-
groups={},
|
|
4177
|
-
disable_geoip=None,
|
|
4178
|
-
)
|
|
4179
|
-
|
|
4180
|
-
# Reset mocks for further tests
|
|
4181
|
-
patch_capture.reset_mock()
|
|
4182
|
-
patch_flags.reset_mock()
|
|
4183
|
-
|
|
4184
|
-
# Call get_feature_flag_payload again for the same user; capture should not be called again because we've already reported an event for this distinct_id + flag
|
|
4185
|
-
client.get_feature_flag_payload(
|
|
4163
|
+
payload = client.get_feature_flag_payload(
|
|
4186
4164
|
key="person-flag",
|
|
4187
4165
|
distinct_id="some-distinct-id",
|
|
4188
4166
|
person_properties={"region": "USA", "name": "Aloha"},
|
|
4189
4167
|
)
|
|
4190
|
-
|
|
4168
|
+
self.assertIsNotNone(payload)
|
|
4191
4169
|
self.assertEqual(patch_capture.call_count, 0)
|
|
4192
|
-
patch_capture.reset_mock()
|
|
4193
|
-
|
|
4194
|
-
# Call get_feature_flag_payload for a different user; capture should be called
|
|
4195
|
-
client.get_feature_flag_payload(
|
|
4196
|
-
key="person-flag",
|
|
4197
|
-
distinct_id="some-distinct-id2",
|
|
4198
|
-
person_properties={"region": "USA", "name": "Aloha"},
|
|
4199
|
-
)
|
|
4200
|
-
|
|
4201
|
-
self.assertEqual(patch_capture.call_count, 1)
|
|
4202
|
-
patch_capture.assert_called_with(
|
|
4203
|
-
"$feature_flag_called",
|
|
4204
|
-
distinct_id="some-distinct-id2",
|
|
4205
|
-
properties={
|
|
4206
|
-
"$feature_flag": "person-flag",
|
|
4207
|
-
"$feature_flag_response": True,
|
|
4208
|
-
"locally_evaluated": True,
|
|
4209
|
-
"$feature/person-flag": True,
|
|
4210
|
-
},
|
|
4211
|
-
groups={},
|
|
4212
|
-
disable_geoip=None,
|
|
4213
|
-
)
|
|
4214
|
-
|
|
4215
|
-
patch_capture.reset_mock()
|
|
4216
4170
|
|
|
4217
4171
|
@mock.patch("posthog.client.flags")
|
|
4218
4172
|
def test_fallback_to_api_in_get_feature_flag_payload_when_flag_has_static_cohort(
|
posthog/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
posthog/__init__.py,sha256=onbj2NNWstUUvWuwd8SdLQ2QIXMcB4JihsePbYj2Z64,28042
|
|
2
2
|
posthog/args.py,sha256=JUt0vbtF33IzLt3ARgsxMEYYnZo3RNS_LcK4-CjWaco,3298
|
|
3
|
-
posthog/client.py,sha256=
|
|
3
|
+
posthog/client.py,sha256=CPxZ12s-MEfWQi01px5doZuhyEpj-OhlW8ZMZZ8NZPM,82087
|
|
4
4
|
posthog/consumer.py,sha256=fdteMZ-deJGMpaQmHyznw_cwQG2Vvld1tmN9LUkZPrY,4608
|
|
5
5
|
posthog/contexts.py,sha256=22z4KySFCTwPbz4OYsd_8EJpoc2H91NiLq9cscSvFfw,12600
|
|
6
6
|
posthog/exception_capture.py,sha256=pmKtjQ6QY6zs4u_-ZA4H1gCyR3iI4sfqCQG_jwe_bKo,1774
|
|
@@ -12,11 +12,11 @@ posthog/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
12
12
|
posthog/request.py,sha256=_WdffuI4BgRL9UvbEEi-4uxpFW3P4h7PRDpYM0lawVU,11817
|
|
13
13
|
posthog/types.py,sha256=OxGHSmmhVYwA7ecmJXUznDCZ1c4gAGtERzSLSYlyQFM,11540
|
|
14
14
|
posthog/utils.py,sha256=-0w-OLcCaoldkbBebPzQyBzLJSo9G9yBOg8NDVz7La8,16088
|
|
15
|
-
posthog/version.py,sha256=
|
|
15
|
+
posthog/version.py,sha256=ENylQGscv-j9khghHOVhotuHnhrpkR8QWKZsS1RqbJs,87
|
|
16
16
|
posthog/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
posthog/ai/sanitization.py,sha256=Dpx_5gKZfDS38KjmK1C0lvvjm9N8Pp_oIxusac888-g,6057
|
|
18
18
|
posthog/ai/types.py,sha256=arX98hR1PIPeJ3vFikxTlACIh1xPp6aEUw1gBLcKoB0,3273
|
|
19
|
-
posthog/ai/utils.py,sha256=
|
|
19
|
+
posthog/ai/utils.py,sha256=s5h4NpXfs5SA-9J7LsirAhES8bQAJvL2hD-tU0PXPsU,21547
|
|
20
20
|
posthog/ai/anthropic/__init__.py,sha256=8nTvETZzkfW-P3zBMmp06GOHs0N-xyOGu7Oa4di_lno,669
|
|
21
21
|
posthog/ai/anthropic/anthropic.py,sha256=UWyM6ryl5_VNQImaBi1RHN7tKXwkqaxy4yaXyPSkDp8,8669
|
|
22
22
|
posthog/ai/anthropic/anthropic_async.py,sha256=ppWHiVp4hTl62Zr3jIwXXidOsqhrwx6iHM3ukG7WiPM,8789
|
|
@@ -29,29 +29,29 @@ posthog/ai/gemini/gemini_converter.py,sha256=JptTOV98s3V0jPKKHVRktze1i0RaSbkkOT0
|
|
|
29
29
|
posthog/ai/langchain/__init__.py,sha256=9CqAwLynTGj3ASAR80C3PmdTdrYGmu99tz0JL-HPFgI,70
|
|
30
30
|
posthog/ai/langchain/callbacks.py,sha256=EhjXTok2M2w5k5x9XFycl-bUMA1gdZx6FxHAY-HZ6bo,31367
|
|
31
31
|
posthog/ai/openai/__init__.py,sha256=u4OuUT7k1NgFj0TrxjuyegOg7a_UA8nAU6a-Hszr0OM,490
|
|
32
|
-
posthog/ai/openai/openai.py,sha256=
|
|
33
|
-
posthog/ai/openai/openai_async.py,sha256=
|
|
32
|
+
posthog/ai/openai/openai.py,sha256=HWqd-uL0cRqwXVE06enRjqnxvIIxc-b_JLI41aimX6A,21324
|
|
33
|
+
posthog/ai/openai/openai_async.py,sha256=b-65PQkIvYaA-AMOBorENL_wa3vh5c5pdSGPG29Nn2s,23655
|
|
34
34
|
posthog/ai/openai/openai_converter.py,sha256=Miaqc9uzLRV_v-1zzn8Iqy8JsKb4l2Tjnw_1atp-8Xs,25828
|
|
35
35
|
posthog/ai/openai/openai_providers.py,sha256=zQIFTXHS2-dBKQX7FZxTFo7rIj5iiN7VHm9_2RzuDs8,3941
|
|
36
36
|
posthog/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
37
|
posthog/integrations/django.py,sha256=9X37yCF-T-MXUsxqkqjBWG3kdgOCyQYYNJQG_ZlwbRg,12633
|
|
38
38
|
posthog/test/__init__.py,sha256=VYgM6xPbJbvS-xhIcDiBRs0MFC9V_jT65uNeerCz_rM,299
|
|
39
39
|
posthog/test/test_before_send.py,sha256=3546WKlk8rF6bhvqhwcxAsjJovDw0Hf8yTvcYGbrhyI,7912
|
|
40
|
-
posthog/test/test_client.py,sha256=
|
|
40
|
+
posthog/test/test_client.py,sha256=n7v0Wn9d55CKhBgiU5eBdQi1WP6qdeihUbOCBkc0R5Q,102841
|
|
41
41
|
posthog/test/test_consumer.py,sha256=HRDXSH0IPpCfo5yHs23n-0VzFyGSjWBKLEa8XNtU3_Y,7080
|
|
42
42
|
posthog/test/test_contexts.py,sha256=GDYpQNGhdzyA3--ia3WPao_4dqyLUpkWm1NMVm2L-So,7004
|
|
43
43
|
posthog/test/test_exception_capture.py,sha256=nqG33mnxpMrSfPxXGoK6hz3yrQu3Yr-pV7r5_yYBZ68,13305
|
|
44
44
|
posthog/test/test_feature_flag.py,sha256=yIMJkoRtdJr91Y6Rb0PPlpZWBIR394TgWhccnlf-vYE,6815
|
|
45
45
|
posthog/test/test_feature_flag_result.py,sha256=KCQHismwddFWl-PHtRpZzcL5M45q_oUeHsST-zxzjkI,33321
|
|
46
|
-
posthog/test/test_feature_flags.py,sha256=
|
|
46
|
+
posthog/test/test_feature_flags.py,sha256=1V5jLY2Py3pCY3dVwqTt1aQRgZQTV1mX3bNUYQcCVkE,220956
|
|
47
47
|
posthog/test/test_flag_definition_cache.py,sha256=_ssIKtrgNw3WsHv-GQNd_Nk-luDxAWgOVnAOMb8gWP8,21883
|
|
48
48
|
posthog/test/test_module.py,sha256=CERR0dTPGsAmd7YBxK0yKeB2Zr2b_Lv7hNQoeJauc9I,813
|
|
49
49
|
posthog/test/test_request.py,sha256=vrZSayStAAcTr05h2ci3Y8qmKDIV2umBdiJqhr3NPp0,25176
|
|
50
50
|
posthog/test/test_size_limited_dict.py,sha256=Wom7BkzpHmusHilZy0SV3PNzhw7ucuQgqrx86jf8euo,765
|
|
51
51
|
posthog/test/test_types.py,sha256=csLuBiz6RMV36cpg9LVIor4Khq6MfjjGxYXodx5VttY,7586
|
|
52
52
|
posthog/test/test_utils.py,sha256=YqAnXaMHxzEV_D3AHhs-RXnZYzdEN7kdIlpOT6Ti6t0,9714
|
|
53
|
-
posthog-7.4.
|
|
54
|
-
posthog-7.4.
|
|
55
|
-
posthog-7.4.
|
|
56
|
-
posthog-7.4.
|
|
57
|
-
posthog-7.4.
|
|
53
|
+
posthog-7.4.1.dist-info/licenses/LICENSE,sha256=wGf9JBotDkSygFj43m49oiKlFnpMnn97keiZKF-40vE,2450
|
|
54
|
+
posthog-7.4.1.dist-info/METADATA,sha256=GOel_mx2Me3Txlgt5pn0-XoffXQ9VVtSCFoPX-DfUQc,6010
|
|
55
|
+
posthog-7.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
56
|
+
posthog-7.4.1.dist-info/top_level.txt,sha256=7FBLsRjIUHVKQsXIhozuI3k-mun1tapp8iZO9EmUPEw,8
|
|
57
|
+
posthog-7.4.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|