truesight-sdk 0.1.0a1__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.
@@ -0,0 +1,66 @@
1
+ # Rust
2
+ /target/
3
+ **/*.rs.bk
4
+ *.pdb
5
+
6
+ # Node
7
+ node_modules/
8
+ dist/
9
+ build/
10
+ *.tsbuildinfo
11
+
12
+ # Environment
13
+ .env
14
+ .env.local
15
+ .env.*.local
16
+ !.env.example
17
+
18
+ # IDE
19
+ .idea/
20
+ .vscode/
21
+ *.swp
22
+ *.swo
23
+ *~
24
+
25
+ # OS
26
+ .DS_Store
27
+ Thumbs.db
28
+
29
+ # Gradle / KMM
30
+ .gradle/
31
+ sdks/kmm/build/
32
+ sdks/kmm/**/build/
33
+ sdks/kmm/local.properties
34
+ sdks/kmm/.kotlin/
35
+ **/*.klib
36
+
37
+ # Python SDK
38
+ sdks/python/.venv/
39
+ sdks/python/dist/
40
+ sdks/python/build/
41
+ **/*.egg-info/
42
+ sdks/python/.pytest_cache/
43
+ sdks/python/.mypy_cache/
44
+ sdks/python/.ruff_cache/
45
+ **/__pycache__/
46
+
47
+ # Database
48
+ *.db
49
+ *.sqlite
50
+
51
+ # Logs
52
+ *.log
53
+
54
+ # Docker volumes
55
+ clickhouse_data/
56
+ postgres_data/
57
+
58
+ # Lock files (pnpm is canonical, npm lock is SDK-local)
59
+ # sdks/web/package-lock.json is committed for npm publish
60
+
61
+ # Superpowers brainstorm artifacts
62
+ .superpowers/
63
+
64
+ # Claude Code
65
+ .claude/
66
+ .gstack/
@@ -0,0 +1,199 @@
1
+ Metadata-Version: 2.4
2
+ Name: truesight-sdk
3
+ Version: 0.1.0a1
4
+ Summary: Server-side Python SDK for TrueSight analytics ingestion
5
+ Project-URL: Homepage, https://github.com/komorebitech/cf-truesight
6
+ Project-URL: Source, https://github.com/komorebitech/cf-truesight/tree/master/sdks/python
7
+ Project-URL: Issues, https://github.com/komorebitech/cf-truesight/issues
8
+ Author-email: Cityflo Engineering <tech@cityflo.com>
9
+ License-Expression: MIT
10
+ Keywords: analytics,cityflo,event-tracking,truesight
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: requests>=2.28
23
+ Requires-Dist: urllib3>=2.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: mypy>=1.10; extra == 'dev'
26
+ Requires-Dist: pytest>=8.0; extra == 'dev'
27
+ Requires-Dist: responses>=0.25; extra == 'dev'
28
+ Requires-Dist: ruff>=0.6; extra == 'dev'
29
+ Requires-Dist: types-requests; extra == 'dev'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # truesight-sdk
33
+
34
+ Server-side Python SDK for [TrueSight](https://github.com/komorebitech/cf-truesight) analytics ingestion.
35
+
36
+ Designed for backends that emit events on behalf of authenticated users (Django, Flask, FastAPI, Airflow DAGs, management commands). Sync by design — if you need async, wrap calls in your own task queue.
37
+
38
+ ## Installation
39
+
40
+ ```bash
41
+ pip install truesight-sdk
42
+ ```
43
+
44
+ Python 3.10+.
45
+
46
+ ## Quick Start
47
+
48
+ ### Single event
49
+
50
+ ```python
51
+ from truesight_sdk import TrueSightClient
52
+
53
+ client = TrueSightClient(
54
+ api_key="ts_server_live_...",
55
+ base_url="https://ingest.truesight.example.com",
56
+ )
57
+
58
+ client.track(
59
+ event_name="Purchased Lite Pack",
60
+ user_id=str(customer.pk),
61
+ properties={"plan_slug": "5-30-days", "amount": 1200},
62
+ )
63
+ ```
64
+
65
+ ### User profile update (identify)
66
+
67
+ ```python
68
+ client.identify(
69
+ user_id=str(customer.pk),
70
+ email=customer.email,
71
+ properties={
72
+ "home_locality": "Andheri",
73
+ "favourite_route": "M1",
74
+ "weekly_subscription_active": True,
75
+ },
76
+ )
77
+ ```
78
+
79
+ This upserts the user's row in `truesight.user_profiles` (latest-write-wins merge of the `properties` blob) and also appends a `$identify` event to the stream for history.
80
+
81
+ ### Batched ingestion (Airflow / cron / bulk syncs)
82
+
83
+ For workloads that emit many events in a tight loop, use `BatchingClient` to amortize HTTP overhead:
84
+
85
+ ```python
86
+ from truesight_sdk import BatchingClient, TrueSightClient
87
+
88
+ inner = TrueSightClient(api_key="ts_server_live_...", base_url="...")
89
+
90
+ with BatchingClient(inner, batch_size=100, flush_interval_seconds=5.0) as batcher:
91
+ for customer in qs.iterator():
92
+ batcher.identify(
93
+ user_id=str(customer.pk),
94
+ properties=build_profile(customer),
95
+ )
96
+ # Buffers drain on context exit.
97
+ ```
98
+
99
+ `BatchingClient` is thread-safe; multiple producer threads can call `track()` / `identify()` concurrently.
100
+
101
+ ### Reading events (admin queries)
102
+
103
+ The SDK also wraps TrueSight's admin event-query endpoint for read-path consumers:
104
+
105
+ ```python
106
+ from truesight_sdk import AdminQueryClient
107
+
108
+ reader = AdminQueryClient(admin_token="...", base_url="https://admin.truesight.example.com")
109
+
110
+ page = reader.fetch_events(
111
+ project_id="b219fb11-9a63-4843-8126-a3dc05b330a5",
112
+ event_name="Purchased Lite Pack",
113
+ from_=datetime(2026, 5, 1, tzinfo=timezone.utc),
114
+ to=datetime(2026, 5, 28, tzinfo=timezone.utc),
115
+ limit=500,
116
+ )
117
+ ```
118
+
119
+ ## API Keys
120
+
121
+ Server keys are scoped — they can only call `/v1/server/*` endpoints. Issue one via the CLI:
122
+
123
+ ```bash
124
+ truesight projects api-keys create --scope server --label "<your service>"
125
+ ```
126
+
127
+ The plaintext key is returned **once** at creation time. Store it in your secrets manager.
128
+
129
+ ## Error Handling
130
+
131
+ All errors subclass `TrueSightError`:
132
+
133
+ ```python
134
+ from truesight_sdk import (
135
+ AuthError, # 401 — bad / revoked key
136
+ Forbidden, # 403 — wrong scope for this endpoint
137
+ ValidationError, # 400/422 — payload rejected
138
+ RateLimited, # 429 — slow down (after SDK's own retry budget)
139
+ ServerError, # 5xx — TrueSight is degraded (after retries)
140
+ TrueSightError, # base class — catch this to handle any SDK error
141
+ )
142
+
143
+ try:
144
+ client.track("x", user_id="42")
145
+ except RateLimited:
146
+ schedule_retry(...)
147
+ except TrueSightError as exc:
148
+ log.exception("truesight ingest failed", request_id=exc.request_id)
149
+ ```
150
+
151
+ Every error carries `status_code`, `request_id` (when the server returned one), and `response_body` for log correlation.
152
+
153
+ ## Retry Idempotency
154
+
155
+ The SDK auto-generates a fresh `event_id` (UUIDv4) for every event when one isn't supplied. If you need retry idempotency (e.g. inside a Celery task that may run twice), pass an explicit `event_id` stable across retries:
156
+
157
+ ```python
158
+ from truesight_sdk import TrackEvent
159
+ from uuid import uuid5, NAMESPACE_URL
160
+
161
+ stable_id = uuid5(NAMESPACE_URL, f"booking-confirmed:{booking.pk}")
162
+ client.track_batch([
163
+ TrackEvent(
164
+ event_name="Booking Confirmed",
165
+ user_id=str(booking.customer_id),
166
+ event_id=stable_id,
167
+ properties={"booking_id": booking.pk},
168
+ ),
169
+ ])
170
+ ```
171
+
172
+ The server dedups on `(project_id, event_id)` via ClickHouse's `ReplacingMergeTree`, so retries with the same id collapse to a single row.
173
+
174
+ ## Development
175
+
176
+ ```bash
177
+ # Install in dev mode
178
+ pip install -e ".[dev]"
179
+
180
+ # Run unit tests (no network)
181
+ pytest
182
+
183
+ # Run integration tests against a local TrueSight stack
184
+ export TRUESIGHT_BASE_URL=http://localhost:8080
185
+ export TRUESIGHT_API_KEY=ts_server_test_...
186
+ pytest -m integration
187
+
188
+ # Lint + typecheck
189
+ ruff check src/ tests/
190
+ mypy src/
191
+ ```
192
+
193
+ ## Versioning
194
+
195
+ Semver. `0.x` is alpha — the public API may shift; pin the patch version until `1.0`.
196
+
197
+ ## License
198
+
199
+ MIT — see top-level repo.
@@ -0,0 +1,168 @@
1
+ # truesight-sdk
2
+
3
+ Server-side Python SDK for [TrueSight](https://github.com/komorebitech/cf-truesight) analytics ingestion.
4
+
5
+ Designed for backends that emit events on behalf of authenticated users (Django, Flask, FastAPI, Airflow DAGs, management commands). Sync by design — if you need async, wrap calls in your own task queue.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install truesight-sdk
11
+ ```
12
+
13
+ Python 3.10+.
14
+
15
+ ## Quick Start
16
+
17
+ ### Single event
18
+
19
+ ```python
20
+ from truesight_sdk import TrueSightClient
21
+
22
+ client = TrueSightClient(
23
+ api_key="ts_server_live_...",
24
+ base_url="https://ingest.truesight.example.com",
25
+ )
26
+
27
+ client.track(
28
+ event_name="Purchased Lite Pack",
29
+ user_id=str(customer.pk),
30
+ properties={"plan_slug": "5-30-days", "amount": 1200},
31
+ )
32
+ ```
33
+
34
+ ### User profile update (identify)
35
+
36
+ ```python
37
+ client.identify(
38
+ user_id=str(customer.pk),
39
+ email=customer.email,
40
+ properties={
41
+ "home_locality": "Andheri",
42
+ "favourite_route": "M1",
43
+ "weekly_subscription_active": True,
44
+ },
45
+ )
46
+ ```
47
+
48
+ This upserts the user's row in `truesight.user_profiles` (latest-write-wins merge of the `properties` blob) and also appends a `$identify` event to the stream for history.
49
+
50
+ ### Batched ingestion (Airflow / cron / bulk syncs)
51
+
52
+ For workloads that emit many events in a tight loop, use `BatchingClient` to amortize HTTP overhead:
53
+
54
+ ```python
55
+ from truesight_sdk import BatchingClient, TrueSightClient
56
+
57
+ inner = TrueSightClient(api_key="ts_server_live_...", base_url="...")
58
+
59
+ with BatchingClient(inner, batch_size=100, flush_interval_seconds=5.0) as batcher:
60
+ for customer in qs.iterator():
61
+ batcher.identify(
62
+ user_id=str(customer.pk),
63
+ properties=build_profile(customer),
64
+ )
65
+ # Buffers drain on context exit.
66
+ ```
67
+
68
+ `BatchingClient` is thread-safe; multiple producer threads can call `track()` / `identify()` concurrently.
69
+
70
+ ### Reading events (admin queries)
71
+
72
+ The SDK also wraps TrueSight's admin event-query endpoint for read-path consumers:
73
+
74
+ ```python
75
+ from truesight_sdk import AdminQueryClient
76
+
77
+ reader = AdminQueryClient(admin_token="...", base_url="https://admin.truesight.example.com")
78
+
79
+ page = reader.fetch_events(
80
+ project_id="b219fb11-9a63-4843-8126-a3dc05b330a5",
81
+ event_name="Purchased Lite Pack",
82
+ from_=datetime(2026, 5, 1, tzinfo=timezone.utc),
83
+ to=datetime(2026, 5, 28, tzinfo=timezone.utc),
84
+ limit=500,
85
+ )
86
+ ```
87
+
88
+ ## API Keys
89
+
90
+ Server keys are scoped — they can only call `/v1/server/*` endpoints. Issue one via the CLI:
91
+
92
+ ```bash
93
+ truesight projects api-keys create --scope server --label "<your service>"
94
+ ```
95
+
96
+ The plaintext key is returned **once** at creation time. Store it in your secrets manager.
97
+
98
+ ## Error Handling
99
+
100
+ All errors subclass `TrueSightError`:
101
+
102
+ ```python
103
+ from truesight_sdk import (
104
+ AuthError, # 401 — bad / revoked key
105
+ Forbidden, # 403 — wrong scope for this endpoint
106
+ ValidationError, # 400/422 — payload rejected
107
+ RateLimited, # 429 — slow down (after SDK's own retry budget)
108
+ ServerError, # 5xx — TrueSight is degraded (after retries)
109
+ TrueSightError, # base class — catch this to handle any SDK error
110
+ )
111
+
112
+ try:
113
+ client.track("x", user_id="42")
114
+ except RateLimited:
115
+ schedule_retry(...)
116
+ except TrueSightError as exc:
117
+ log.exception("truesight ingest failed", request_id=exc.request_id)
118
+ ```
119
+
120
+ Every error carries `status_code`, `request_id` (when the server returned one), and `response_body` for log correlation.
121
+
122
+ ## Retry Idempotency
123
+
124
+ The SDK auto-generates a fresh `event_id` (UUIDv4) for every event when one isn't supplied. If you need retry idempotency (e.g. inside a Celery task that may run twice), pass an explicit `event_id` stable across retries:
125
+
126
+ ```python
127
+ from truesight_sdk import TrackEvent
128
+ from uuid import uuid5, NAMESPACE_URL
129
+
130
+ stable_id = uuid5(NAMESPACE_URL, f"booking-confirmed:{booking.pk}")
131
+ client.track_batch([
132
+ TrackEvent(
133
+ event_name="Booking Confirmed",
134
+ user_id=str(booking.customer_id),
135
+ event_id=stable_id,
136
+ properties={"booking_id": booking.pk},
137
+ ),
138
+ ])
139
+ ```
140
+
141
+ The server dedups on `(project_id, event_id)` via ClickHouse's `ReplacingMergeTree`, so retries with the same id collapse to a single row.
142
+
143
+ ## Development
144
+
145
+ ```bash
146
+ # Install in dev mode
147
+ pip install -e ".[dev]"
148
+
149
+ # Run unit tests (no network)
150
+ pytest
151
+
152
+ # Run integration tests against a local TrueSight stack
153
+ export TRUESIGHT_BASE_URL=http://localhost:8080
154
+ export TRUESIGHT_API_KEY=ts_server_test_...
155
+ pytest -m integration
156
+
157
+ # Lint + typecheck
158
+ ruff check src/ tests/
159
+ mypy src/
160
+ ```
161
+
162
+ ## Versioning
163
+
164
+ Semver. `0.x` is alpha — the public API may shift; pin the patch version until `1.0`.
165
+
166
+ ## License
167
+
168
+ MIT — see top-level repo.
@@ -0,0 +1,83 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "truesight-sdk"
7
+ description = "Server-side Python SDK for TrueSight analytics ingestion"
8
+ readme = "README.md"
9
+ license = "MIT"
10
+ requires-python = ">=3.10"
11
+ authors = [
12
+ { name = "Cityflo Engineering", email = "tech@cityflo.com" },
13
+ ]
14
+ keywords = ["analytics", "truesight", "event-tracking", "cityflo"]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Topic :: Software Development :: Libraries :: Python Modules",
25
+ "Typing :: Typed",
26
+ ]
27
+ dependencies = [
28
+ "requests>=2.28",
29
+ "urllib3>=2.0",
30
+ ]
31
+ dynamic = ["version"]
32
+
33
+ [project.urls]
34
+ Homepage = "https://github.com/komorebitech/cf-truesight"
35
+ Source = "https://github.com/komorebitech/cf-truesight/tree/master/sdks/python"
36
+ Issues = "https://github.com/komorebitech/cf-truesight/issues"
37
+
38
+ [project.optional-dependencies]
39
+ dev = [
40
+ "pytest>=8.0",
41
+ "responses>=0.25",
42
+ "ruff>=0.6",
43
+ "mypy>=1.10",
44
+ "types-requests",
45
+ ]
46
+
47
+ [tool.hatch.version]
48
+ path = "src/truesight_sdk/_version.py"
49
+
50
+ [tool.hatch.build.targets.wheel]
51
+ packages = ["src/truesight_sdk"]
52
+
53
+ [tool.hatch.build.targets.sdist]
54
+ include = [
55
+ "/src",
56
+ "/tests",
57
+ "/README.md",
58
+ "/pyproject.toml",
59
+ ]
60
+
61
+ [tool.ruff]
62
+ line-length = 100
63
+ target-version = "py310"
64
+
65
+ [tool.ruff.lint]
66
+ select = ["E", "F", "I", "N", "UP", "B", "SIM", "RUF"]
67
+ ignore = ["E501"]
68
+
69
+ [tool.mypy]
70
+ python_version = "3.10"
71
+ strict = true
72
+ warn_unreachable = true
73
+ disallow_untyped_decorators = false
74
+
75
+ [[tool.mypy.overrides]]
76
+ module = ["responses.*"]
77
+ ignore_missing_imports = true
78
+
79
+ [tool.pytest.ini_options]
80
+ testpaths = ["tests"]
81
+ markers = [
82
+ "integration: integration test that requires a running TrueSight instance (skipped unless TRUESIGHT_BASE_URL is set)",
83
+ ]
@@ -0,0 +1,54 @@
1
+ """TrueSight Python SDK — server-side analytics ingestion.
2
+
3
+ This SDK targets server-to-server use cases (Django/Flask/FastAPI backends,
4
+ Airflow DAGs, management commands) that emit events on behalf of authenticated
5
+ users. It is intentionally sync; if you need an async wrapper, wire it up via
6
+ your own task queue (e.g. Celery).
7
+
8
+ Quick start:
9
+
10
+ from truesight_sdk import TrueSightClient
11
+
12
+ client = TrueSightClient(
13
+ api_key="ts_server_live_...",
14
+ base_url="https://ingest.truesight.example.com",
15
+ )
16
+ client.track(
17
+ event_name="Purchased Lite Pack",
18
+ user_id=str(customer.pk),
19
+ properties={"plan_slug": "5-30-days", "amount": 1200},
20
+ )
21
+
22
+ For bulk-sync workloads (Airflow DAGs, nightly profile syncs), use
23
+ ``BatchingClient`` to amortize HTTP overhead across many events.
24
+ """
25
+
26
+ from truesight_sdk._version import __version__
27
+ from truesight_sdk.batching import BatchingClient
28
+ from truesight_sdk.client import TrueSightClient
29
+ from truesight_sdk.errors import (
30
+ AuthError,
31
+ Forbidden,
32
+ RateLimited,
33
+ ServerError,
34
+ TrueSightError,
35
+ ValidationError,
36
+ )
37
+ from truesight_sdk.models import EventType, IdentifyEvent, TrackEvent
38
+ from truesight_sdk.query import AdminQueryClient
39
+
40
+ __all__ = [
41
+ "AdminQueryClient",
42
+ "AuthError",
43
+ "BatchingClient",
44
+ "EventType",
45
+ "Forbidden",
46
+ "IdentifyEvent",
47
+ "RateLimited",
48
+ "ServerError",
49
+ "TrackEvent",
50
+ "TrueSightClient",
51
+ "TrueSightError",
52
+ "ValidationError",
53
+ "__version__",
54
+ ]
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0a1"