posthoganalytics 5.3.0__tar.gz → 5.4.0__tar.gz

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.
Files changed (58) hide show
  1. {posthoganalytics-5.3.0/posthoganalytics.egg-info → posthoganalytics-5.4.0}/PKG-INFO +1 -1
  2. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/client.py +3 -0
  3. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/test/test_client.py +322 -0
  4. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/version.py +1 -1
  5. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0/posthoganalytics.egg-info}/PKG-INFO +1 -1
  6. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/LICENSE +0 -0
  7. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/MANIFEST.in +0 -0
  8. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/README.md +0 -0
  9. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/__init__.py +0 -0
  10. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/ai/__init__.py +0 -0
  11. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/ai/anthropic/__init__.py +0 -0
  12. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/ai/anthropic/anthropic.py +0 -0
  13. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/ai/anthropic/anthropic_async.py +0 -0
  14. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/ai/anthropic/anthropic_providers.py +0 -0
  15. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/ai/gemini/__init__.py +0 -0
  16. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/ai/gemini/gemini.py +0 -0
  17. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/ai/langchain/__init__.py +0 -0
  18. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/ai/langchain/callbacks.py +0 -0
  19. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/ai/openai/__init__.py +0 -0
  20. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/ai/openai/openai.py +0 -0
  21. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/ai/openai/openai_async.py +0 -0
  22. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/ai/openai/openai_providers.py +0 -0
  23. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/ai/utils.py +0 -0
  24. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/consumer.py +0 -0
  25. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/exception_capture.py +0 -0
  26. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/exception_integrations/__init__.py +0 -0
  27. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/exception_integrations/django.py +0 -0
  28. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/exception_utils.py +0 -0
  29. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/feature_flags.py +0 -0
  30. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/integrations/__init__.py +0 -0
  31. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/integrations/django.py +0 -0
  32. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/poller.py +0 -0
  33. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/py.typed +0 -0
  34. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/request.py +0 -0
  35. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/scopes.py +0 -0
  36. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/test/__init__.py +0 -0
  37. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/test/test_before_send.py +0 -0
  38. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/test/test_consumer.py +0 -0
  39. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/test/test_exception_capture.py +0 -0
  40. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/test/test_feature_flag.py +0 -0
  41. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/test/test_feature_flag_result.py +0 -0
  42. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/test/test_feature_flags.py +0 -0
  43. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/test/test_module.py +0 -0
  44. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/test/test_request.py +0 -0
  45. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/test/test_scopes.py +0 -0
  46. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/test/test_size_limited_dict.py +0 -0
  47. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/test/test_types.py +0 -0
  48. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/test/test_utils.py +0 -0
  49. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/types.py +0 -0
  50. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics/utils.py +0 -0
  51. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics.egg-info/SOURCES.txt +0 -0
  52. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics.egg-info/dependency_links.txt +0 -0
  53. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics.egg-info/requires.txt +0 -0
  54. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/posthoganalytics.egg-info/top_level.txt +0 -0
  55. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/pyproject.toml +0 -0
  56. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/setup.cfg +0 -0
  57. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/setup.py +0 -0
  58. {posthoganalytics-5.3.0 → posthoganalytics-5.4.0}/setup_analytics.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: posthoganalytics
3
- Version: 5.3.0
3
+ Version: 5.4.0
4
4
  Summary: Integrate PostHog into any python application.
5
5
  Home-page: https://github.com/posthog/posthog-python
6
6
  Author: Posthog
@@ -651,6 +651,9 @@ class Client(object):
651
651
  require("distinct_id", distinct_id, ID_TYPES)
652
652
  require("properties", properties, dict)
653
653
 
654
+ if "$session_id" not in properties and get_context_session_id():
655
+ properties["$session_id"] = get_context_session_id()
656
+
654
657
  require("url", url, string_types)
655
658
  properties["$current_url"] = url
656
659
 
@@ -2,6 +2,7 @@ import time
2
2
  import unittest
3
3
  from datetime import datetime
4
4
  from uuid import uuid4
5
+ from posthoganalytics.scopes import get_context_session_id, set_context_session, new_context
5
6
 
6
7
  import mock
7
8
  import six
@@ -939,6 +940,255 @@ class TestClient(unittest.TestCase):
939
940
  self.assertEqual(msg["uuid"], "new-uuid")
940
941
  self.assertEqual(msg["distinct_id"], "distinct_id")
941
942
 
943
+ @parameterized.expand(
944
+ [
945
+ # test_name, session_id, additional_properties, expected_properties
946
+ ("basic_session_id", "test-session-123", {}, {}),
947
+ (
948
+ "session_id_with_other_properties",
949
+ "test-session-456",
950
+ {
951
+ "custom_prop": "custom_value",
952
+ "$process_person_profile": False,
953
+ "$current_url": "https://example.com",
954
+ },
955
+ {
956
+ "custom_prop": "custom_value",
957
+ "$process_person_profile": False,
958
+ "$current_url": "https://example.com",
959
+ },
960
+ ),
961
+ ("session_id_uuid_format", str(uuid4()), {}, {}),
962
+ ("session_id_numeric_string", "1234567890", {}, {}),
963
+ ("session_id_empty_string", "", {}, {}),
964
+ ("session_id_with_special_chars", "session-123_test.id", {}, {}),
965
+ ]
966
+ )
967
+ def test_capture_with_session_id_variations(
968
+ self, test_name, session_id, additional_properties, expected_properties
969
+ ):
970
+ client = self.client
971
+
972
+ properties = {"$session_id": session_id, **additional_properties}
973
+ success, msg = client.capture(
974
+ "distinct_id", "python test event", properties=properties
975
+ )
976
+ client.flush()
977
+
978
+ self.assertTrue(success)
979
+ self.assertFalse(self.failed)
980
+ self.assertEqual(msg["event"], "python test event")
981
+ self.assertEqual(msg["distinct_id"], "distinct_id")
982
+ self.assertEqual(msg["properties"]["$session_id"], session_id)
983
+ self.assertEqual(msg["properties"]["$lib"], "posthog-python")
984
+ self.assertEqual(msg["properties"]["$lib_version"], VERSION)
985
+
986
+ # Check additional expected properties
987
+ for key, value in expected_properties.items():
988
+ self.assertEqual(msg["properties"][key], value)
989
+
990
+ def test_session_id_preserved_with_groups(self):
991
+ client = self.client
992
+ session_id = "group-session-101"
993
+
994
+ success, msg = client.capture(
995
+ "distinct_id",
996
+ "test_event",
997
+ properties={"$session_id": session_id},
998
+ groups={"company": "id:5", "instance": "app.posthog.com"},
999
+ )
1000
+ client.flush()
1001
+
1002
+ self.assertTrue(success)
1003
+ self.assertEqual(msg["properties"]["$session_id"], session_id)
1004
+ self.assertEqual(
1005
+ msg["properties"]["$groups"],
1006
+ {"company": "id:5", "instance": "app.posthog.com"},
1007
+ )
1008
+
1009
+ def test_session_id_with_anonymous_event(self):
1010
+ client = self.client
1011
+ session_id = "anonymous-session-202"
1012
+
1013
+ success, msg = client.capture(
1014
+ "distinct_id",
1015
+ "anonymous_event",
1016
+ properties={"$session_id": session_id, "$process_person_profile": False},
1017
+ )
1018
+ client.flush()
1019
+
1020
+ self.assertTrue(success)
1021
+ self.assertEqual(msg["properties"]["$session_id"], session_id)
1022
+ self.assertEqual(msg["properties"]["$process_person_profile"], False)
1023
+
1024
+ def test_page_with_session_id(self):
1025
+ client = self.client
1026
+ session_id = "page-session-303"
1027
+
1028
+ success, msg = client.page(
1029
+ "distinct_id",
1030
+ "https://posthog.com/contact",
1031
+ properties={"$session_id": session_id, "page_type": "contact"},
1032
+ )
1033
+ client.flush()
1034
+
1035
+ self.assertTrue(success)
1036
+ self.assertFalse(self.failed)
1037
+ self.assertEqual(msg["event"], "$pageview")
1038
+ self.assertEqual(msg["distinct_id"], "distinct_id")
1039
+ self.assertEqual(msg["properties"]["$session_id"], session_id)
1040
+ self.assertEqual(
1041
+ msg["properties"]["$current_url"], "https://posthog.com/contact"
1042
+ )
1043
+ self.assertEqual(msg["properties"]["page_type"], "contact")
1044
+
1045
+ @parameterized.expand(
1046
+ [
1047
+ # test_name, event_name, session_id, additional_properties, expected_additional_properties
1048
+ (
1049
+ "screen_event",
1050
+ "$screen",
1051
+ "special-session-505",
1052
+ {"$screen_name": "HomeScreen"},
1053
+ {"$screen_name": "HomeScreen"},
1054
+ ),
1055
+ (
1056
+ "survey_event",
1057
+ "survey sent",
1058
+ "survey-session-606",
1059
+ {
1060
+ "$survey_id": "survey_123",
1061
+ "$survey_questions": [
1062
+ {"id": "q1", "question": "How likely are you to recommend us?"}
1063
+ ],
1064
+ },
1065
+ {"$survey_id": "survey_123"},
1066
+ ),
1067
+ (
1068
+ "complex_properties_event",
1069
+ "complex_event",
1070
+ "mixed-session-707",
1071
+ {
1072
+ "$current_url": "https://example.com/page",
1073
+ "$process_person_profile": True,
1074
+ "custom_property": "custom_value",
1075
+ "numeric_property": 42,
1076
+ "boolean_property": True,
1077
+ },
1078
+ {
1079
+ "$current_url": "https://example.com/page",
1080
+ "$process_person_profile": True,
1081
+ "custom_property": "custom_value",
1082
+ "numeric_property": 42,
1083
+ "boolean_property": True,
1084
+ },
1085
+ ),
1086
+ (
1087
+ "csp_violation",
1088
+ "$csp_violation",
1089
+ "csp-session-789",
1090
+ {
1091
+ "$csp_version": "1.0",
1092
+ "$current_url": "https://example.com/page",
1093
+ "$process_person_profile": False,
1094
+ "$raw_user_agent": "Mozilla/5.0 Test Agent",
1095
+ "$csp_document_url": "https://example.com/page",
1096
+ "$csp_blocked_url": "https://malicious.com/script.js",
1097
+ "$csp_violated_directive": "script-src",
1098
+ },
1099
+ {
1100
+ "$csp_version": "1.0",
1101
+ "$current_url": "https://example.com/page",
1102
+ "$process_person_profile": False,
1103
+ "$raw_user_agent": "Mozilla/5.0 Test Agent",
1104
+ "$csp_document_url": "https://example.com/page",
1105
+ "$csp_blocked_url": "https://malicious.com/script.js",
1106
+ "$csp_violated_directive": "script-src",
1107
+ },
1108
+ ),
1109
+ ]
1110
+ )
1111
+ def test_session_id_with_different_event_types(
1112
+ self,
1113
+ test_name,
1114
+ event_name,
1115
+ session_id,
1116
+ additional_properties,
1117
+ expected_additional_properties,
1118
+ ):
1119
+ client = self.client
1120
+
1121
+ properties = {"$session_id": session_id, **additional_properties}
1122
+ success, msg = client.capture("distinct_id", event_name, properties=properties)
1123
+ client.flush()
1124
+
1125
+ self.assertTrue(success)
1126
+ self.assertEqual(msg["event"], event_name)
1127
+ self.assertEqual(msg["properties"]["$session_id"], session_id)
1128
+
1129
+ # Check additional expected properties
1130
+ for key, value in expected_additional_properties.items():
1131
+ self.assertEqual(msg["properties"][key], value)
1132
+
1133
+ # Verify system properties are still added
1134
+ self.assertEqual(msg["properties"]["$lib"], "posthog-python")
1135
+ self.assertEqual(msg["properties"]["$lib_version"], VERSION)
1136
+
1137
+ @parameterized.expand(
1138
+ [
1139
+ # test_name, super_properties, event_session_id, expected_session_id, expected_super_props
1140
+ (
1141
+ "super_properties_override_session_id",
1142
+ {"$session_id": "super-session", "source": "test"},
1143
+ "event-session-808",
1144
+ "super-session",
1145
+ {"source": "test"},
1146
+ ),
1147
+ (
1148
+ "no_super_properties_conflict",
1149
+ {"source": "test", "version": "1.0"},
1150
+ "event-session-909",
1151
+ "event-session-909",
1152
+ {"source": "test", "version": "1.0"},
1153
+ ),
1154
+ (
1155
+ "empty_super_properties",
1156
+ {},
1157
+ "event-session-111",
1158
+ "event-session-111",
1159
+ {},
1160
+ ),
1161
+ (
1162
+ "super_properties_with_other_dollar_props",
1163
+ {"$current_url": "https://super.com", "source": "test"},
1164
+ "event-session-222",
1165
+ "event-session-222",
1166
+ {"$current_url": "https://super.com", "source": "test"},
1167
+ ),
1168
+ ]
1169
+ )
1170
+ def test_session_id_with_super_properties_variations(
1171
+ self,
1172
+ test_name,
1173
+ super_properties,
1174
+ event_session_id,
1175
+ expected_session_id,
1176
+ expected_super_props,
1177
+ ):
1178
+ client = Client(FAKE_TEST_API_KEY, super_properties=super_properties)
1179
+
1180
+ success, msg = client.capture(
1181
+ "distinct_id", "test_event", properties={"$session_id": event_session_id}
1182
+ )
1183
+ client.flush()
1184
+
1185
+ self.assertTrue(success)
1186
+ self.assertEqual(msg["properties"]["$session_id"], expected_session_id)
1187
+
1188
+ # Check expected super properties are present
1189
+ for key, value in expected_super_props.items():
1190
+ self.assertEqual(msg["properties"][key], value)
1191
+
942
1192
  def test_flush(self):
943
1193
  client = self.client
944
1194
  # set up the consumer with more requests than a single batch will allow
@@ -1397,3 +1647,75 @@ class TestClient(unittest.TestCase):
1397
1647
  "errorsWhileComputingFlags": False,
1398
1648
  "requestId": "test-id",
1399
1649
  }
1650
+
1651
+ def test_set_context_session_with_capture(self):
1652
+ with new_context():
1653
+ set_context_session("context-session-123")
1654
+
1655
+ success, msg = self.client.capture(
1656
+ "distinct_id", "test_event", {"custom_prop": "value"}
1657
+ )
1658
+ self.client.flush()
1659
+
1660
+ self.assertTrue(success)
1661
+ self.assertEqual(msg["properties"]["$session_id"], "context-session-123")
1662
+
1663
+ def test_set_context_session_with_page(self):
1664
+ with new_context():
1665
+ set_context_session("page-context-session-456")
1666
+
1667
+ success, msg = self.client.page("distinct_id", "https://example.com/page")
1668
+ self.client.flush()
1669
+
1670
+ self.assertTrue(success)
1671
+ self.assertEqual(
1672
+ msg["properties"]["$session_id"], "page-context-session-456"
1673
+ )
1674
+
1675
+ def test_set_context_session_with_page_explicit_properties(self):
1676
+ with new_context():
1677
+ set_context_session("page-explicit-session-789")
1678
+
1679
+ properties = {
1680
+ "$session_id": get_context_session_id(),
1681
+ "page_type": "landing",
1682
+ }
1683
+ success, msg = self.client.page(
1684
+ "distinct_id", "https://example.com/landing", properties
1685
+ )
1686
+ self.client.flush()
1687
+
1688
+ self.assertTrue(success)
1689
+ self.assertEqual(
1690
+ msg["properties"]["$session_id"], "page-explicit-session-789"
1691
+ )
1692
+
1693
+ def test_set_context_session_override_in_capture(self):
1694
+ """Test that explicit session ID overrides context session ID in capture"""
1695
+ from posthoganalytics.scopes import set_context_session, new_context
1696
+
1697
+ with new_context():
1698
+ set_context_session("context-session-override")
1699
+
1700
+ success, msg = self.client.capture(
1701
+ "distinct_id",
1702
+ "test_event",
1703
+ {"$session_id": "explicit-session-override", "custom_prop": "value"},
1704
+ )
1705
+ self.client.flush()
1706
+
1707
+ self.assertTrue(success)
1708
+ self.assertEqual(
1709
+ msg["properties"]["$session_id"], "explicit-session-override"
1710
+ )
1711
+
1712
+ def test_set_context_session_with_identify(self):
1713
+ with new_context(capture_exceptions=False):
1714
+ set_context_session("identify-session-555")
1715
+
1716
+ success, msg = self.client.identify("distinct_id", {"trait": "value"})
1717
+ self.client.flush()
1718
+
1719
+ self.assertTrue(success)
1720
+ # In identify, the session ID is added to the $set payload
1721
+ self.assertEqual(msg["$set"]["$session_id"], "identify-session-555")
@@ -1,4 +1,4 @@
1
- VERSION = "5.3.0"
1
+ VERSION = "5.4.0"
2
2
 
3
3
  if __name__ == "__main__":
4
4
  print(VERSION, end="") # noqa: T201
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: posthoganalytics
3
- Version: 5.3.0
3
+ Version: 5.4.0
4
4
  Summary: Integrate PostHog into any python application.
5
5
  Home-page: https://github.com/posthog/posthog-python
6
6
  Author: Posthog