trodo-python 1.0.0__py3-none-any.whl → 1.2.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.
- trodo/__init__.py +177 -134
- trodo/api/async_client.py +96 -96
- trodo/api/endpoints.py +21 -20
- trodo/api/http_client.py +90 -87
- trodo/auto/auto_event_manager.py +134 -134
- trodo/client.py +318 -195
- trodo/managers/group_manager.py +106 -106
- trodo/managers/people_manager.py +77 -77
- trodo/queue/batch_flusher.py +52 -52
- trodo/queue/event_queue.py +32 -32
- trodo/session/server_session.py +74 -74
- trodo/session/session_manager.py +74 -74
- trodo/types.py +154 -79
- trodo/user_context.py +224 -224
- trodo_python-1.2.0.dist-info/METADATA +358 -0
- trodo_python-1.2.0.dist-info/RECORD +23 -0
- trodo_python-1.0.0.dist-info/METADATA +0 -227
- trodo_python-1.0.0.dist-info/RECORD +0 -23
- {trodo_python-1.0.0.dist-info → trodo_python-1.2.0.dist-info}/WHEEL +0 -0
- {trodo_python-1.0.0.dist-info → trodo_python-1.2.0.dist-info}/top_level.txt +0 -0
trodo/user_context.py
CHANGED
|
@@ -1,224 +1,224 @@
|
|
|
1
|
-
"""UserContext — user-bound proxy for all Trodo SDK operations."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import traceback
|
|
6
|
-
from typing import Any, Dict, List, Optional, Union, TYPE_CHECKING
|
|
7
|
-
|
|
8
|
-
from .managers.people_manager import PeopleManager
|
|
9
|
-
from .managers.group_manager import GroupManager, GroupProfile
|
|
10
|
-
from .types import (
|
|
11
|
-
ApiResult,
|
|
12
|
-
IdentifyResult,
|
|
13
|
-
ResetResult,
|
|
14
|
-
WalletAddressResult,
|
|
15
|
-
EventPayload,
|
|
16
|
-
)
|
|
17
|
-
from .session.server_session import now_iso
|
|
18
|
-
|
|
19
|
-
if TYPE_CHECKING:
|
|
20
|
-
from .api.http_client import HttpClient
|
|
21
|
-
from .session.session_manager import SessionManager
|
|
22
|
-
from .queue.event_queue import EventQueue
|
|
23
|
-
from .queue.batch_flusher import BatchFlusher
|
|
24
|
-
from .auto.auto_event_manager import AutoEventManager
|
|
25
|
-
from .types import ServerSession
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class UserContext:
|
|
29
|
-
def __init__(
|
|
30
|
-
self,
|
|
31
|
-
distinct_id: str,
|
|
32
|
-
site_id: str,
|
|
33
|
-
http_client: "HttpClient",
|
|
34
|
-
session_manager: "SessionManager",
|
|
35
|
-
event_queue: Optional["EventQueue"],
|
|
36
|
-
batch_flusher: Optional["BatchFlusher"],
|
|
37
|
-
auto_event_manager: "AutoEventManager",
|
|
38
|
-
session_id: Optional[str] = None,
|
|
39
|
-
) -> None:
|
|
40
|
-
self._distinct_id = distinct_id
|
|
41
|
-
self._site_id = site_id
|
|
42
|
-
self._http = http_client
|
|
43
|
-
self._session_manager = session_manager
|
|
44
|
-
self._event_queue = event_queue
|
|
45
|
-
self._batch_flusher = batch_flusher
|
|
46
|
-
self._auto_event_manager = auto_event_manager
|
|
47
|
-
self._session_id_override = session_id
|
|
48
|
-
self._session: Optional["ServerSession"] = None
|
|
49
|
-
|
|
50
|
-
# Eagerly initialise session
|
|
51
|
-
self._session = self._session_manager.get_or_create(
|
|
52
|
-
distinct_id, site_id, session_id
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
self.people = PeopleManager(
|
|
56
|
-
http_client, site_id, lambda: self._get_distinct_id()
|
|
57
|
-
)
|
|
58
|
-
self._group_manager = GroupManager(
|
|
59
|
-
http_client, site_id, lambda: self._get_distinct_id()
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
def _get_distinct_id(self) -> str:
|
|
63
|
-
if self._session:
|
|
64
|
-
return self._session.distinct_id
|
|
65
|
-
return self._distinct_id
|
|
66
|
-
|
|
67
|
-
def _get_session(self) -> "ServerSession":
|
|
68
|
-
if not self._session:
|
|
69
|
-
self._session = self._session_manager.get_or_create(
|
|
70
|
-
self._distinct_id, self._site_id, self._session_id_override
|
|
71
|
-
)
|
|
72
|
-
return self._session
|
|
73
|
-
|
|
74
|
-
def _send_event(
|
|
75
|
-
self,
|
|
76
|
-
event_name: str,
|
|
77
|
-
properties: Optional[Dict[str, Any]] = None,
|
|
78
|
-
category: str = "custom",
|
|
79
|
-
) -> None:
|
|
80
|
-
session = self._get_session()
|
|
81
|
-
self._session_manager.ensure_confirmed(session, self._http)
|
|
82
|
-
|
|
83
|
-
event = EventPayload(
|
|
84
|
-
event_type="custom",
|
|
85
|
-
event_name=event_name,
|
|
86
|
-
event_category=category,
|
|
87
|
-
session_id=session.session_id,
|
|
88
|
-
user_id=session.distinct_id,
|
|
89
|
-
custom_properties=properties or {},
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
if self._event_queue and self._batch_flusher:
|
|
93
|
-
should_flush = self._event_queue.enqueue(event)
|
|
94
|
-
if should_flush:
|
|
95
|
-
self._batch_flusher.flush()
|
|
96
|
-
else:
|
|
97
|
-
self._http.post_event(event)
|
|
98
|
-
|
|
99
|
-
# --------------------------------------------------------------------------
|
|
100
|
-
# Event Tracking
|
|
101
|
-
# --------------------------------------------------------------------------
|
|
102
|
-
|
|
103
|
-
def track(
|
|
104
|
-
self,
|
|
105
|
-
event_name: str,
|
|
106
|
-
properties: Optional[Dict[str, Any]] = None,
|
|
107
|
-
category: str = "custom",
|
|
108
|
-
) -> None:
|
|
109
|
-
self._send_event(event_name, properties, category)
|
|
110
|
-
|
|
111
|
-
def track_event(
|
|
112
|
-
self,
|
|
113
|
-
event_name: str,
|
|
114
|
-
properties: Optional[Dict[str, Any]] = None,
|
|
115
|
-
category: str = "custom",
|
|
116
|
-
) -> None:
|
|
117
|
-
"""Alias for track() — matches frontend SDK naming."""
|
|
118
|
-
self._send_event(event_name, properties, category)
|
|
119
|
-
|
|
120
|
-
# --------------------------------------------------------------------------
|
|
121
|
-
# Identity
|
|
122
|
-
# --------------------------------------------------------------------------
|
|
123
|
-
|
|
124
|
-
def identify(self, identify_id: str) -> IdentifyResult:
|
|
125
|
-
session = self._get_session()
|
|
126
|
-
self._session_manager.ensure_confirmed(session, self._http)
|
|
127
|
-
|
|
128
|
-
result = self._http.post_identify({
|
|
129
|
-
"siteId": self._site_id,
|
|
130
|
-
"sessionId": session.session_id,
|
|
131
|
-
"userId": session.distinct_id,
|
|
132
|
-
"distinctId": session.distinct_id,
|
|
133
|
-
"identifyId": identify_id,
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
new_distinct_id = result.get("newDistinctId") or result.get("distinctId")
|
|
137
|
-
if new_distinct_id and new_distinct_id != session.distinct_id:
|
|
138
|
-
session.distinct_id = new_distinct_id
|
|
139
|
-
|
|
140
|
-
return result
|
|
141
|
-
|
|
142
|
-
def wallet_address(self, wallet_addr: str) -> WalletAddressResult:
|
|
143
|
-
session = self._get_session()
|
|
144
|
-
self._session_manager.ensure_confirmed(session, self._http)
|
|
145
|
-
|
|
146
|
-
return self._http.post_wallet_address({
|
|
147
|
-
"siteId": self._site_id,
|
|
148
|
-
"sessionId": session.session_id,
|
|
149
|
-
"userId": session.distinct_id,
|
|
150
|
-
"distinctId": session.distinct_id,
|
|
151
|
-
"walletAddress": wallet_addr,
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
def reset(self) -> ResetResult:
|
|
155
|
-
session = self._get_session()
|
|
156
|
-
result = self._http.post_reset({
|
|
157
|
-
"siteId": self._site_id,
|
|
158
|
-
"sessionId": session.session_id,
|
|
159
|
-
"userId": session.distinct_id,
|
|
160
|
-
"distinctId": session.distinct_id,
|
|
161
|
-
})
|
|
162
|
-
self._session_manager.invalidate(self._distinct_id)
|
|
163
|
-
self._session = None
|
|
164
|
-
return result
|
|
165
|
-
|
|
166
|
-
# --------------------------------------------------------------------------
|
|
167
|
-
# People — accessible via user.people.set(...) etc.
|
|
168
|
-
# --------------------------------------------------------------------------
|
|
169
|
-
|
|
170
|
-
# --------------------------------------------------------------------------
|
|
171
|
-
# Groups
|
|
172
|
-
# --------------------------------------------------------------------------
|
|
173
|
-
|
|
174
|
-
def set_group(self, group_key: str, group_id: Union[str, List[str]]) -> ApiResult:
|
|
175
|
-
self._get_session()
|
|
176
|
-
return self._group_manager.set_group(group_key, group_id)
|
|
177
|
-
|
|
178
|
-
def add_group(self, group_key: str, group_id: str) -> ApiResult:
|
|
179
|
-
self._get_session()
|
|
180
|
-
return self._group_manager.add_group(group_key, group_id)
|
|
181
|
-
|
|
182
|
-
def remove_group(self, group_key: str, group_id: str) -> ApiResult:
|
|
183
|
-
self._get_session()
|
|
184
|
-
return self._group_manager.remove_group(group_key, group_id)
|
|
185
|
-
|
|
186
|
-
def get_group(self, group_key: str, group_id: str) -> GroupProfile:
|
|
187
|
-
return self._group_manager.get_group(group_key, group_id)
|
|
188
|
-
|
|
189
|
-
# --------------------------------------------------------------------------
|
|
190
|
-
# Error capture
|
|
191
|
-
# --------------------------------------------------------------------------
|
|
192
|
-
|
|
193
|
-
def capture_error(
|
|
194
|
-
self,
|
|
195
|
-
error: Exception,
|
|
196
|
-
severity: str = "error",
|
|
197
|
-
) -> None:
|
|
198
|
-
session = self._get_session()
|
|
199
|
-
self._auto_event_manager.track_error(
|
|
200
|
-
error,
|
|
201
|
-
error_type=type(error).__name__,
|
|
202
|
-
severity=severity,
|
|
203
|
-
distinct_id=session.distinct_id,
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
# --------------------------------------------------------------------------
|
|
207
|
-
# Auto events (per-context toggle)
|
|
208
|
-
# --------------------------------------------------------------------------
|
|
209
|
-
|
|
210
|
-
def enable_auto_events(self) -> None:
|
|
211
|
-
self._auto_event_manager.enable()
|
|
212
|
-
|
|
213
|
-
def disable_auto_events(self) -> None:
|
|
214
|
-
self._auto_event_manager.disable()
|
|
215
|
-
|
|
216
|
-
# --------------------------------------------------------------------------
|
|
217
|
-
# Session info
|
|
218
|
-
# --------------------------------------------------------------------------
|
|
219
|
-
|
|
220
|
-
def get_session_id(self) -> Optional[str]:
|
|
221
|
-
return self._session.session_id if self._session else None
|
|
222
|
-
|
|
223
|
-
def get_current_distinct_id(self) -> str:
|
|
224
|
-
return self._get_distinct_id()
|
|
1
|
+
"""UserContext — user-bound proxy for all Trodo SDK operations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import traceback
|
|
6
|
+
from typing import Any, Dict, List, Optional, Union, TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from .managers.people_manager import PeopleManager
|
|
9
|
+
from .managers.group_manager import GroupManager, GroupProfile
|
|
10
|
+
from .types import (
|
|
11
|
+
ApiResult,
|
|
12
|
+
IdentifyResult,
|
|
13
|
+
ResetResult,
|
|
14
|
+
WalletAddressResult,
|
|
15
|
+
EventPayload,
|
|
16
|
+
)
|
|
17
|
+
from .session.server_session import now_iso
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from .api.http_client import HttpClient
|
|
21
|
+
from .session.session_manager import SessionManager
|
|
22
|
+
from .queue.event_queue import EventQueue
|
|
23
|
+
from .queue.batch_flusher import BatchFlusher
|
|
24
|
+
from .auto.auto_event_manager import AutoEventManager
|
|
25
|
+
from .types import ServerSession
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class UserContext:
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
distinct_id: str,
|
|
32
|
+
site_id: str,
|
|
33
|
+
http_client: "HttpClient",
|
|
34
|
+
session_manager: "SessionManager",
|
|
35
|
+
event_queue: Optional["EventQueue"],
|
|
36
|
+
batch_flusher: Optional["BatchFlusher"],
|
|
37
|
+
auto_event_manager: "AutoEventManager",
|
|
38
|
+
session_id: Optional[str] = None,
|
|
39
|
+
) -> None:
|
|
40
|
+
self._distinct_id = distinct_id
|
|
41
|
+
self._site_id = site_id
|
|
42
|
+
self._http = http_client
|
|
43
|
+
self._session_manager = session_manager
|
|
44
|
+
self._event_queue = event_queue
|
|
45
|
+
self._batch_flusher = batch_flusher
|
|
46
|
+
self._auto_event_manager = auto_event_manager
|
|
47
|
+
self._session_id_override = session_id
|
|
48
|
+
self._session: Optional["ServerSession"] = None
|
|
49
|
+
|
|
50
|
+
# Eagerly initialise session
|
|
51
|
+
self._session = self._session_manager.get_or_create(
|
|
52
|
+
distinct_id, site_id, session_id
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
self.people = PeopleManager(
|
|
56
|
+
http_client, site_id, lambda: self._get_distinct_id()
|
|
57
|
+
)
|
|
58
|
+
self._group_manager = GroupManager(
|
|
59
|
+
http_client, site_id, lambda: self._get_distinct_id()
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def _get_distinct_id(self) -> str:
|
|
63
|
+
if self._session:
|
|
64
|
+
return self._session.distinct_id
|
|
65
|
+
return self._distinct_id
|
|
66
|
+
|
|
67
|
+
def _get_session(self) -> "ServerSession":
|
|
68
|
+
if not self._session:
|
|
69
|
+
self._session = self._session_manager.get_or_create(
|
|
70
|
+
self._distinct_id, self._site_id, self._session_id_override
|
|
71
|
+
)
|
|
72
|
+
return self._session
|
|
73
|
+
|
|
74
|
+
def _send_event(
|
|
75
|
+
self,
|
|
76
|
+
event_name: str,
|
|
77
|
+
properties: Optional[Dict[str, Any]] = None,
|
|
78
|
+
category: str = "custom",
|
|
79
|
+
) -> None:
|
|
80
|
+
session = self._get_session()
|
|
81
|
+
self._session_manager.ensure_confirmed(session, self._http)
|
|
82
|
+
|
|
83
|
+
event = EventPayload(
|
|
84
|
+
event_type="custom",
|
|
85
|
+
event_name=event_name,
|
|
86
|
+
event_category=category,
|
|
87
|
+
session_id=session.session_id,
|
|
88
|
+
user_id=session.distinct_id,
|
|
89
|
+
custom_properties=properties or {},
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
if self._event_queue and self._batch_flusher:
|
|
93
|
+
should_flush = self._event_queue.enqueue(event)
|
|
94
|
+
if should_flush:
|
|
95
|
+
self._batch_flusher.flush()
|
|
96
|
+
else:
|
|
97
|
+
self._http.post_event(event)
|
|
98
|
+
|
|
99
|
+
# --------------------------------------------------------------------------
|
|
100
|
+
# Event Tracking
|
|
101
|
+
# --------------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
def track(
|
|
104
|
+
self,
|
|
105
|
+
event_name: str,
|
|
106
|
+
properties: Optional[Dict[str, Any]] = None,
|
|
107
|
+
category: str = "custom",
|
|
108
|
+
) -> None:
|
|
109
|
+
self._send_event(event_name, properties, category)
|
|
110
|
+
|
|
111
|
+
def track_event(
|
|
112
|
+
self,
|
|
113
|
+
event_name: str,
|
|
114
|
+
properties: Optional[Dict[str, Any]] = None,
|
|
115
|
+
category: str = "custom",
|
|
116
|
+
) -> None:
|
|
117
|
+
"""Alias for track() — matches frontend SDK naming."""
|
|
118
|
+
self._send_event(event_name, properties, category)
|
|
119
|
+
|
|
120
|
+
# --------------------------------------------------------------------------
|
|
121
|
+
# Identity
|
|
122
|
+
# --------------------------------------------------------------------------
|
|
123
|
+
|
|
124
|
+
def identify(self, identify_id: str) -> IdentifyResult:
|
|
125
|
+
session = self._get_session()
|
|
126
|
+
self._session_manager.ensure_confirmed(session, self._http)
|
|
127
|
+
|
|
128
|
+
result = self._http.post_identify({
|
|
129
|
+
"siteId": self._site_id,
|
|
130
|
+
"sessionId": session.session_id,
|
|
131
|
+
"userId": session.distinct_id,
|
|
132
|
+
"distinctId": session.distinct_id,
|
|
133
|
+
"identifyId": identify_id,
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
new_distinct_id = result.get("newDistinctId") or result.get("distinctId")
|
|
137
|
+
if new_distinct_id and new_distinct_id != session.distinct_id:
|
|
138
|
+
session.distinct_id = new_distinct_id
|
|
139
|
+
|
|
140
|
+
return result
|
|
141
|
+
|
|
142
|
+
def wallet_address(self, wallet_addr: str) -> WalletAddressResult:
|
|
143
|
+
session = self._get_session()
|
|
144
|
+
self._session_manager.ensure_confirmed(session, self._http)
|
|
145
|
+
|
|
146
|
+
return self._http.post_wallet_address({
|
|
147
|
+
"siteId": self._site_id,
|
|
148
|
+
"sessionId": session.session_id,
|
|
149
|
+
"userId": session.distinct_id,
|
|
150
|
+
"distinctId": session.distinct_id,
|
|
151
|
+
"walletAddress": wallet_addr,
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
def reset(self) -> ResetResult:
|
|
155
|
+
session = self._get_session()
|
|
156
|
+
result = self._http.post_reset({
|
|
157
|
+
"siteId": self._site_id,
|
|
158
|
+
"sessionId": session.session_id,
|
|
159
|
+
"userId": session.distinct_id,
|
|
160
|
+
"distinctId": session.distinct_id,
|
|
161
|
+
})
|
|
162
|
+
self._session_manager.invalidate(self._distinct_id)
|
|
163
|
+
self._session = None
|
|
164
|
+
return result
|
|
165
|
+
|
|
166
|
+
# --------------------------------------------------------------------------
|
|
167
|
+
# People — accessible via user.people.set(...) etc.
|
|
168
|
+
# --------------------------------------------------------------------------
|
|
169
|
+
|
|
170
|
+
# --------------------------------------------------------------------------
|
|
171
|
+
# Groups
|
|
172
|
+
# --------------------------------------------------------------------------
|
|
173
|
+
|
|
174
|
+
def set_group(self, group_key: str, group_id: Union[str, List[str]]) -> ApiResult:
|
|
175
|
+
self._get_session()
|
|
176
|
+
return self._group_manager.set_group(group_key, group_id)
|
|
177
|
+
|
|
178
|
+
def add_group(self, group_key: str, group_id: str) -> ApiResult:
|
|
179
|
+
self._get_session()
|
|
180
|
+
return self._group_manager.add_group(group_key, group_id)
|
|
181
|
+
|
|
182
|
+
def remove_group(self, group_key: str, group_id: str) -> ApiResult:
|
|
183
|
+
self._get_session()
|
|
184
|
+
return self._group_manager.remove_group(group_key, group_id)
|
|
185
|
+
|
|
186
|
+
def get_group(self, group_key: str, group_id: str) -> GroupProfile:
|
|
187
|
+
return self._group_manager.get_group(group_key, group_id)
|
|
188
|
+
|
|
189
|
+
# --------------------------------------------------------------------------
|
|
190
|
+
# Error capture
|
|
191
|
+
# --------------------------------------------------------------------------
|
|
192
|
+
|
|
193
|
+
def capture_error(
|
|
194
|
+
self,
|
|
195
|
+
error: Exception,
|
|
196
|
+
severity: str = "error",
|
|
197
|
+
) -> None:
|
|
198
|
+
session = self._get_session()
|
|
199
|
+
self._auto_event_manager.track_error(
|
|
200
|
+
error,
|
|
201
|
+
error_type=type(error).__name__,
|
|
202
|
+
severity=severity,
|
|
203
|
+
distinct_id=session.distinct_id,
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
# --------------------------------------------------------------------------
|
|
207
|
+
# Auto events (per-context toggle)
|
|
208
|
+
# --------------------------------------------------------------------------
|
|
209
|
+
|
|
210
|
+
def enable_auto_events(self) -> None:
|
|
211
|
+
self._auto_event_manager.enable()
|
|
212
|
+
|
|
213
|
+
def disable_auto_events(self) -> None:
|
|
214
|
+
self._auto_event_manager.disable()
|
|
215
|
+
|
|
216
|
+
# --------------------------------------------------------------------------
|
|
217
|
+
# Session info
|
|
218
|
+
# --------------------------------------------------------------------------
|
|
219
|
+
|
|
220
|
+
def get_session_id(self) -> Optional[str]:
|
|
221
|
+
return self._session.session_id if self._session else None
|
|
222
|
+
|
|
223
|
+
def get_current_distinct_id(self) -> str:
|
|
224
|
+
return self._get_distinct_id()
|