posthoganalytics 5.3.0__py3-none-any.whl → 5.4.0__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.
@@ -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
@@ -1,5 +1,5 @@
1
1
  posthoganalytics/__init__.py,sha256=1VxnAzs1ndcud3A2RkZ_Pys1mJcCEqmRSzdR7kbk06E,19680
2
- posthoganalytics/client.py,sha256=-Z_-NeSkkRCUVvE7nHRjtSHZWPH9PX4qEcCG6P-rIHM,48908
2
+ posthoganalytics/client.py,sha256=if7J6pyp8XaBrHYXiyqgIRTpJ7bVDskw69kfIRfg9E4,49047
3
3
  posthoganalytics/consumer.py,sha256=CiNbJBdyW9jER3ZYCKbX-JFmEDXlE1lbDy1MSl43-a0,4617
4
4
  posthoganalytics/exception_capture.py,sha256=tO--YrFqaMqH4h2SYsm8Oeo3KUUky6JyxA0ubo-_xE0,2724
5
5
  posthoganalytics/exception_utils.py,sha256=T7vh88VWO1gWES5VkE8uR7zKOez6KBC-kRDnSPQKA0A,29680
@@ -10,7 +10,7 @@ posthoganalytics/request.py,sha256=TaeySYpcvHMf5Ftf5KqqlO0VPJpirKBCRrThlS04Kew,6
10
10
  posthoganalytics/scopes.py,sha256=rx79WerS6vmNP2IDR1dfZQVNDHJ3xUnVz6be1YWD2gM,8194
11
11
  posthoganalytics/types.py,sha256=INxWBOEQc0xgPcap6FdQNSU7zuQBmKShYaGzyuHKql8,9128
12
12
  posthoganalytics/utils.py,sha256=4qw-5PMYVXS66367olLYn8IqGNKcwfevv5n7w1Mjh2Q,5587
13
- posthoganalytics/version.py,sha256=rrsydwaQj7PshCWM4M5yZUI3xsFY7yM6CvHkqP6HYN8,87
13
+ posthoganalytics/version.py,sha256=I85JOowUqLrC4sAZT80knLum_fFLg-MOlCH3fUL7AoE,87
14
14
  posthoganalytics/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  posthoganalytics/ai/utils.py,sha256=5-2XfmetCs0v9otBoux7-IEG933wAnKLSGS6oYLqCkw,19529
16
16
  posthoganalytics/ai/anthropic/__init__.py,sha256=fFhDOiRzTXzGQlgnrRDL-4yKC8EYIl8NW4a2QNR6xRU,368
@@ -31,7 +31,7 @@ posthoganalytics/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
31
31
  posthoganalytics/integrations/django.py,sha256=IT3qiFfzK_XqEW0XgXNabMBZRj2viwf97Yc9aTuVxqg,4934
32
32
  posthoganalytics/test/__init__.py,sha256=VYgM6xPbJbvS-xhIcDiBRs0MFC9V_jT65uNeerCz_rM,299
33
33
  posthoganalytics/test/test_before_send.py,sha256=UrapOB5SHL6N6yleNnIa-H37Ih603Xa-bVJ4AdgjQRM,5959
34
- posthoganalytics/test/test_client.py,sha256=BSePdUaizqiR5ivSLh7bOzlI8T46Khi3ntN9urqV744,52702
34
+ posthoganalytics/test/test_client.py,sha256=4adaYx9R-mm32n3cQLz6X1cZzQQCxFs9b1FRycdMQJE,64716
35
35
  posthoganalytics/test/test_consumer.py,sha256=HGMfU9PzQ5ZAe_R3kHnZNsMvD7jUjHL-gie0isrvMMk,7107
36
36
  posthoganalytics/test/test_exception_capture.py,sha256=SQ14AFhqe_VaS34C1IMqEFWq04HOTrjwQ0JRX31R_ik,2148
37
37
  posthoganalytics/test/test_feature_flag.py,sha256=9RQwB5eCvVAGrrO7UnR3Z1OidP_YoL4iBl3A83fuAig,6824
@@ -43,8 +43,8 @@ posthoganalytics/test/test_scopes.py,sha256=e3hk1QJ8RRs9FZB6A_LidCzQigkVhZTxSXl9
43
43
  posthoganalytics/test/test_size_limited_dict.py,sha256=-5IQjIEr_-Dql24M0HusdR_XroOMrtgiT0v6ZQCRvzo,774
44
44
  posthoganalytics/test/test_types.py,sha256=bRPHdwVpP7hu7emsplU8UVyzSQptv6PaG5lAoOD_BtM,7595
45
45
  posthoganalytics/test/test_utils.py,sha256=GYLJp4ud_RP31-NnYJINOY0G0ra-QcGJszpp9MTyYq8,5428
46
- posthoganalytics-5.3.0.dist-info/licenses/LICENSE,sha256=wGf9JBotDkSygFj43m49oiKlFnpMnn97keiZKF-40vE,2450
47
- posthoganalytics-5.3.0.dist-info/METADATA,sha256=THPYNG0T9SpKOuhjc2ccUpRIjwCxJhSISIll38q_yx8,5692
48
- posthoganalytics-5.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
49
- posthoganalytics-5.3.0.dist-info/top_level.txt,sha256=8QsNIqIkBh1p2TXvKp0Em9ZLZKwe3uIqCETyW4s1GOE,17
50
- posthoganalytics-5.3.0.dist-info/RECORD,,
46
+ posthoganalytics-5.4.0.dist-info/licenses/LICENSE,sha256=wGf9JBotDkSygFj43m49oiKlFnpMnn97keiZKF-40vE,2450
47
+ posthoganalytics-5.4.0.dist-info/METADATA,sha256=75Pd57i7U7L0hP2qbEqmpNcg3qrpBIF6xH-Qs8y6CXw,5692
48
+ posthoganalytics-5.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
49
+ posthoganalytics-5.4.0.dist-info/top_level.txt,sha256=8QsNIqIkBh1p2TXvKp0Em9ZLZKwe3uIqCETyW4s1GOE,17
50
+ posthoganalytics-5.4.0.dist-info/RECORD,,