tinybird-sdk 0.1.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 (85) hide show
  1. tinybird_sdk-0.1.0/PKG-INFO +929 -0
  2. tinybird_sdk-0.1.0/README.md +919 -0
  3. tinybird_sdk-0.1.0/pyproject.toml +29 -0
  4. tinybird_sdk-0.1.0/src/tinybird_sdk/__init__.py +99 -0
  5. tinybird_sdk-0.1.0/src/tinybird_sdk/_http.py +176 -0
  6. tinybird_sdk-0.1.0/src/tinybird_sdk/api/__init__.py +78 -0
  7. tinybird_sdk-0.1.0/src/tinybird_sdk/api/api.py +492 -0
  8. tinybird_sdk-0.1.0/src/tinybird_sdk/api/branches.py +162 -0
  9. tinybird_sdk-0.1.0/src/tinybird_sdk/api/build.py +121 -0
  10. tinybird_sdk-0.1.0/src/tinybird_sdk/api/dashboard.py +47 -0
  11. tinybird_sdk-0.1.0/src/tinybird_sdk/api/deploy.py +232 -0
  12. tinybird_sdk-0.1.0/src/tinybird_sdk/api/fetcher.py +21 -0
  13. tinybird_sdk-0.1.0/src/tinybird_sdk/api/local.py +154 -0
  14. tinybird_sdk-0.1.0/src/tinybird_sdk/api/regions.py +34 -0
  15. tinybird_sdk-0.1.0/src/tinybird_sdk/api/resources.py +417 -0
  16. tinybird_sdk-0.1.0/src/tinybird_sdk/api/tokens.py +67 -0
  17. tinybird_sdk-0.1.0/src/tinybird_sdk/api/workspaces.py +45 -0
  18. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/__init__.py +62 -0
  19. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/auth.py +142 -0
  20. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/branch_store.py +94 -0
  21. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/__init__.py +34 -0
  22. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/branch.py +103 -0
  23. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/build.py +185 -0
  24. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/clear.py +67 -0
  25. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/deploy.py +79 -0
  26. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/dev.py +97 -0
  27. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/generate.py +131 -0
  28. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/info.py +93 -0
  29. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/init.py +154 -0
  30. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/login.py +56 -0
  31. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/migrate.py +46 -0
  32. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/open_dashboard.py +65 -0
  33. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/preview.py +200 -0
  34. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/pull.py +121 -0
  35. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/config.py +244 -0
  36. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/config_loader.py +95 -0
  37. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/config_types.py +15 -0
  38. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/env.py +49 -0
  39. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/git.py +80 -0
  40. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/index.py +92 -0
  41. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/output.py +205 -0
  42. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/region_selector.py +72 -0
  43. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/utils/__init__.py +23 -0
  44. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/utils/package_manager.py +154 -0
  45. tinybird_sdk-0.1.0/src/tinybird_sdk/cli/utils/schema_validation.py +179 -0
  46. tinybird_sdk-0.1.0/src/tinybird_sdk/client/__init__.py +19 -0
  47. tinybird_sdk-0.1.0/src/tinybird_sdk/client/base.py +230 -0
  48. tinybird_sdk-0.1.0/src/tinybird_sdk/client/preview.py +111 -0
  49. tinybird_sdk-0.1.0/src/tinybird_sdk/client/tokens.py +40 -0
  50. tinybird_sdk-0.1.0/src/tinybird_sdk/client/types.py +128 -0
  51. tinybird_sdk-0.1.0/src/tinybird_sdk/codegen/__init__.py +28 -0
  52. tinybird_sdk-0.1.0/src/tinybird_sdk/codegen/index.py +198 -0
  53. tinybird_sdk-0.1.0/src/tinybird_sdk/codegen/type_mapper.py +147 -0
  54. tinybird_sdk-0.1.0/src/tinybird_sdk/codegen/utils.py +156 -0
  55. tinybird_sdk-0.1.0/src/tinybird_sdk/generator/__init__.py +45 -0
  56. tinybird_sdk-0.1.0/src/tinybird_sdk/generator/client.py +93 -0
  57. tinybird_sdk-0.1.0/src/tinybird_sdk/generator/connection.py +80 -0
  58. tinybird_sdk-0.1.0/src/tinybird_sdk/generator/datasource.py +193 -0
  59. tinybird_sdk-0.1.0/src/tinybird_sdk/generator/include_paths.py +107 -0
  60. tinybird_sdk-0.1.0/src/tinybird_sdk/generator/index.py +148 -0
  61. tinybird_sdk-0.1.0/src/tinybird_sdk/generator/loader.py +255 -0
  62. tinybird_sdk-0.1.0/src/tinybird_sdk/generator/pipe.py +135 -0
  63. tinybird_sdk-0.1.0/src/tinybird_sdk/infer/__init__.py +15 -0
  64. tinybird_sdk-0.1.0/src/tinybird_sdk/infer/index.py +50 -0
  65. tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/__init__.py +55 -0
  66. tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/discovery.py +140 -0
  67. tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/emit_ts.py +494 -0
  68. tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/parse.py +16 -0
  69. tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/parse_connection.py +213 -0
  70. tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/parse_datasource.py +505 -0
  71. tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/parse_pipe.py +803 -0
  72. tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/parser_utils.py +158 -0
  73. tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/runner.py +317 -0
  74. tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/types.py +223 -0
  75. tinybird_sdk-0.1.0/src/tinybird_sdk/py.typed +0 -0
  76. tinybird_sdk-0.1.0/src/tinybird_sdk/schema/__init__.py +100 -0
  77. tinybird_sdk-0.1.0/src/tinybird_sdk/schema/connection.py +117 -0
  78. tinybird_sdk-0.1.0/src/tinybird_sdk/schema/datasource.py +187 -0
  79. tinybird_sdk-0.1.0/src/tinybird_sdk/schema/engines.py +100 -0
  80. tinybird_sdk-0.1.0/src/tinybird_sdk/schema/params.py +122 -0
  81. tinybird_sdk-0.1.0/src/tinybird_sdk/schema/pipe.py +427 -0
  82. tinybird_sdk-0.1.0/src/tinybird_sdk/schema/project.py +230 -0
  83. tinybird_sdk-0.1.0/src/tinybird_sdk/schema/secret.py +11 -0
  84. tinybird_sdk-0.1.0/src/tinybird_sdk/schema/token.py +28 -0
  85. tinybird_sdk-0.1.0/src/tinybird_sdk/schema/types.py +197 -0
@@ -0,0 +1,929 @@
1
+ Metadata-Version: 2.3
2
+ Name: tinybird-sdk
3
+ Version: 0.1.0
4
+ Summary: Python SDK for Tinybird Forward
5
+ Author: Tinybird
6
+ Author-email: Tinybird <support@tinybird.co>
7
+ Requires-Dist: tinybird
8
+ Requires-Python: >=3.11
9
+ Description-Content-Type: text/markdown
10
+
11
+ # tinybird-sdk (Python)
12
+
13
+ > **Note:** This package is experimental. APIs may change between versions.
14
+
15
+ A Python SDK for defining Tinybird resources with a TypeScript-SDK-like workflow.
16
+ Define your datasources, pipes, and queries in Python and sync them directly to Tinybird.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install tinybird-sdk
22
+ ```
23
+
24
+ ## Requirements
25
+
26
+ - Python `>=3.11`
27
+ - Server-side usage only (do not expose Tinybird credentials in browser code)
28
+
29
+ ## Quick Start
30
+
31
+ ### 1. Initialize your project
32
+
33
+ ```bash
34
+ tinybird init
35
+ ```
36
+
37
+ This creates:
38
+ - `tinybird.config.json` - Configuration file
39
+ - `lib/datasources.py` - Define your datasources
40
+ - `lib/pipes.py` - Define your pipes/endpoints
41
+ - `lib/client.py` - Your Tinybird client module
42
+
43
+ ### 2. Configure your token
44
+
45
+ Create a `.env.local` file:
46
+
47
+ ```env
48
+ TINYBIRD_TOKEN=p.your_token_here
49
+ ```
50
+
51
+ ### 3. Define your datasources
52
+
53
+ ```python
54
+ # lib/datasources.py
55
+ from tinybird_sdk import define_datasource, t, engine
56
+
57
+ page_views = define_datasource(
58
+ "page_views",
59
+ {
60
+ "description": "Page view tracking data",
61
+ "schema": {
62
+ "timestamp": t.date_time(),
63
+ "pathname": t.string(),
64
+ "session_id": t.string(),
65
+ "country": t.string().low_cardinality().nullable(),
66
+ },
67
+ "engine": engine.merge_tree(
68
+ {
69
+ "sorting_key": ["pathname", "timestamp"],
70
+ }
71
+ ),
72
+ },
73
+ )
74
+ ```
75
+
76
+ ### 4. Define your endpoints
77
+
78
+ ```python
79
+ # lib/pipes.py
80
+ from tinybird_sdk import define_endpoint, node, p, t
81
+
82
+ top_pages = define_endpoint(
83
+ "top_pages",
84
+ {
85
+ "description": "Get the most visited pages",
86
+ "params": {
87
+ "start_date": p.date_time(),
88
+ "end_date": p.date_time(),
89
+ "limit": p.int32().optional(10),
90
+ },
91
+ "nodes": [
92
+ node(
93
+ {
94
+ "name": "aggregated",
95
+ "sql": """
96
+ SELECT pathname, count() AS views
97
+ FROM page_views
98
+ WHERE timestamp >= {{DateTime(start_date)}}
99
+ AND timestamp <= {{DateTime(end_date)}}
100
+ GROUP BY pathname
101
+ ORDER BY views DESC
102
+ LIMIT {{Int32(limit, 10)}}
103
+ """,
104
+ }
105
+ )
106
+ ],
107
+ "output": {
108
+ "pathname": t.string(),
109
+ "views": t.uint64(),
110
+ },
111
+ },
112
+ )
113
+ ```
114
+
115
+ ### 5. Create your client
116
+
117
+ ```python
118
+ # lib/client.py
119
+ from tinybird_sdk import Tinybird
120
+ from .datasources import page_views
121
+ from .pipes import top_pages
122
+
123
+ tinybird = Tinybird(
124
+ {
125
+ "datasources": {"page_views": page_views},
126
+ "pipes": {"top_pages": top_pages},
127
+ }
128
+ )
129
+
130
+ __all__ = ["tinybird", "page_views", "top_pages"]
131
+ ```
132
+
133
+ ### 6. Optional: use a stable local import path
134
+
135
+ In larger applications, keep a single module (for example `lib/client.py`) and import from there:
136
+
137
+ ```python
138
+ from lib.client import tinybird
139
+ ```
140
+
141
+ ### 7. Start development
142
+
143
+ ```bash
144
+ tinybird dev
145
+ ```
146
+
147
+ This watches your schema files and syncs changes to Tinybird.
148
+
149
+ ### 8. Use the client
150
+
151
+ ```python
152
+ from lib.client import tinybird
153
+
154
+ # Ingest one row
155
+ tinybird.page_views.ingest(
156
+ {
157
+ "timestamp": "2024-01-15 10:30:00",
158
+ "pathname": "/home",
159
+ "session_id": "abc123",
160
+ "country": "US",
161
+ }
162
+ )
163
+
164
+ # Query endpoint
165
+ result = tinybird.top_pages.query(
166
+ {
167
+ "start_date": "2024-01-01 00:00:00",
168
+ "end_date": "2024-01-31 23:59:59",
169
+ "limit": 5,
170
+ }
171
+ )
172
+ ```
173
+
174
+ ### 9. Manage datasource rows
175
+
176
+ ```python
177
+ from lib.client import tinybird
178
+
179
+ # Datasource accessors support: ingest, append, replace, delete, truncate
180
+
181
+ tinybird.page_views.ingest(
182
+ {
183
+ "timestamp": "2024-01-15 10:30:00",
184
+ "pathname": "/pricing",
185
+ "session_id": "session_123",
186
+ "country": "US",
187
+ }
188
+ )
189
+
190
+ tinybird.page_views.append(
191
+ {
192
+ "url": "https://example.com/page_views.csv",
193
+ }
194
+ )
195
+
196
+ tinybird.page_views.replace(
197
+ {
198
+ "url": "https://example.com/page_views_full_snapshot.csv",
199
+ }
200
+ )
201
+
202
+ tinybird.page_views.delete(
203
+ {
204
+ "delete_condition": "country = 'XX'",
205
+ }
206
+ )
207
+
208
+ tinybird.page_views.delete(
209
+ {
210
+ "delete_condition": "country = 'XX'",
211
+ "dry_run": True,
212
+ }
213
+ )
214
+
215
+ tinybird.page_views.truncate()
216
+ ```
217
+
218
+ ## Public Tinybird API (Optional)
219
+
220
+ If you want a low-level API wrapper decoupled from the high-level client layer,
221
+ use `create_tinybird_api()` directly with `base_url` and `token`:
222
+
223
+ ```python
224
+ from tinybird_sdk import create_tinybird_api
225
+
226
+ api = create_tinybird_api(
227
+ {
228
+ "base_url": "https://api.tinybird.co",
229
+ "token": "p.your_token",
230
+ }
231
+ )
232
+
233
+ # Query endpoint pipe
234
+ top_pages = api.query(
235
+ "top_pages",
236
+ {
237
+ "start_date": "2024-01-01",
238
+ "end_date": "2024-01-31",
239
+ "limit": 5,
240
+ },
241
+ )
242
+
243
+ # Ingest one row
244
+ api.ingest(
245
+ "events",
246
+ {
247
+ "timestamp": "2024-01-15 10:30:00",
248
+ "event_name": "page_view",
249
+ "pathname": "/home",
250
+ },
251
+ )
252
+
253
+ # Ingest retry behavior (disabled by default):
254
+ # - 429 retries use Retry-After / X-RateLimit-Reset headers.
255
+ # - 503 retries use SDK default exponential backoff.
256
+ api.ingest(
257
+ "events",
258
+ {
259
+ "timestamp": "2024-01-15 10:31:00",
260
+ "event_name": "button_click",
261
+ "pathname": "/pricing",
262
+ },
263
+ {
264
+ "max_retries": 3,
265
+ },
266
+ )
267
+
268
+ # Import rows from URL/file
269
+ api.append_datasource(
270
+ "events",
271
+ {
272
+ "url": "https://example.com/events.csv",
273
+ },
274
+ )
275
+
276
+ # Delete rows matching a SQL condition
277
+ api.delete_datasource(
278
+ "events",
279
+ {
280
+ "delete_condition": "event_name = 'test'",
281
+ },
282
+ )
283
+
284
+ # Delete dry run
285
+ api.delete_datasource(
286
+ "events",
287
+ {
288
+ "delete_condition": "event_name = 'test'",
289
+ "dry_run": True,
290
+ },
291
+ )
292
+
293
+ # Truncate datasource
294
+ api.truncate_datasource("events")
295
+
296
+ # Execute raw SQL
297
+ sql_result = api.sql("SELECT count() AS total FROM events")
298
+
299
+ # Optional per-request token override
300
+ workspace_response = api.request_json(
301
+ "/v1/workspace",
302
+ token="p.branch_or_jwt_token",
303
+ )
304
+ ```
305
+
306
+ This Tinybird API is standalone and can be used without `create_client()` or `Tinybird(...)`.
307
+
308
+ ## JWT Token Creation
309
+
310
+ Create short-lived JWT tokens for secure scoped access to Tinybird resources.
311
+
312
+ ```python
313
+ from datetime import datetime, timedelta, timezone
314
+
315
+ from tinybird_sdk import create_client
316
+
317
+ client = create_client(
318
+ {
319
+ "base_url": "https://api.tinybird.co",
320
+ "token": "p.your_admin_token",
321
+ }
322
+ )
323
+
324
+ result = client.tokens.create_jwt(
325
+ {
326
+ "name": "user_123_session",
327
+ "expires_at": datetime.now(tz=timezone.utc) + timedelta(hours=1),
328
+ "scopes": [
329
+ {
330
+ "type": "PIPES:READ",
331
+ "resource": "user_dashboard",
332
+ "fixed_params": {"user_id": 123},
333
+ }
334
+ ],
335
+ "limits": {"rps": 10},
336
+ }
337
+ )
338
+
339
+ jwt_token = result["token"]
340
+ ```
341
+
342
+ ### Scope Types
343
+
344
+ | Scope | Description |
345
+ |-------|-------------|
346
+ | `PIPES:READ` | Read access to a specific pipe endpoint |
347
+ | `DATASOURCES:READ` | Read access to a datasource (with optional `filter`) |
348
+ | `DATASOURCES:APPEND` | Append access to a datasource |
349
+
350
+ ### Scope Options
351
+
352
+ - **`fixed_params`**: For pipes, embed parameters that cannot be overridden by the caller.
353
+ - **`filter`**: For datasources, append a SQL WHERE clause (for example, `"org_id = 'acme'"`).
354
+
355
+ ## CLI Commands
356
+
357
+ This package installs `tinybird` as a runtime dependency.
358
+ `tinybird generate` is handled by this SDK; other commands are delegated to the Tinybird CLI.
359
+
360
+ ### `tinybird init`
361
+
362
+ Initialize a new Tinybird project:
363
+
364
+ ```bash
365
+ tinybird init
366
+ tinybird init --force
367
+ tinybird init --skip-login
368
+ ```
369
+
370
+ ### `tinybird migrate`
371
+
372
+ Migrate local Tinybird datafiles (`.datasource`, `.pipe`, `.connection`) into a Python definitions file.
373
+
374
+ ```bash
375
+ tinybird migrate "tinybird/**/*.datasource" "tinybird/**/*.pipe" "tinybird/**/*.connection"
376
+ tinybird migrate tinybird/legacy --out ./tinybird.migration.py
377
+ tinybird migrate tinybird --dry-run
378
+ ```
379
+
380
+ ### `tinybird dev`
381
+
382
+ ```bash
383
+ tinybird dev
384
+ tinybird dev --local
385
+ tinybird dev --branch
386
+ ```
387
+
388
+ ### `tinybird build`
389
+
390
+ ```bash
391
+ tinybird build
392
+ tinybird build --dry-run
393
+ tinybird build --local
394
+ tinybird build --branch
395
+ ```
396
+
397
+ ### `tinybird deploy`
398
+
399
+ ```bash
400
+ tinybird deploy
401
+ tinybird deploy --check
402
+ tinybird deploy --allow-destructive-operations
403
+ ```
404
+
405
+ ### `tinybird pull`
406
+
407
+ ```bash
408
+ tinybird pull
409
+ tinybird pull --output-dir ./tinybird-datafiles
410
+ tinybird pull --force
411
+ ```
412
+
413
+ ### `tinybird login`
414
+
415
+ ```bash
416
+ tinybird login
417
+ ```
418
+
419
+ ### `tinybird branch`
420
+
421
+ ```bash
422
+ tinybird branch list
423
+ tinybird branch status
424
+ tinybird branch delete <name>
425
+ ```
426
+
427
+ ### `tinybird info`
428
+
429
+ ```bash
430
+ tinybird info
431
+ tinybird info --json
432
+ ```
433
+
434
+ ## Configuration
435
+
436
+ Create a `tinybird.config.json` (or `tinybird.config.py` / `tinybird_config.py` for dynamic logic) in your project root:
437
+
438
+ ```json
439
+ {
440
+ "include": [
441
+ "lib/*.py",
442
+ "tinybird/**/*.datasource",
443
+ "tinybird/**/*.pipe",
444
+ "tinybird/**/*.connection"
445
+ ],
446
+ "token": "${TINYBIRD_TOKEN}",
447
+ "base_url": "https://api.tinybird.co",
448
+ "dev_mode": "branch"
449
+ }
450
+ ```
451
+
452
+ You can mix Python files with raw `.datasource`, `.pipe`, and `.connection` files for incremental migration.
453
+ `include` supports glob patterns.
454
+
455
+ ### Config File Formats
456
+
457
+ Supported config files (search order):
458
+
459
+ | File | Description |
460
+ |------|-------------|
461
+ | `tinybird.config.py` | Python config with dynamic logic |
462
+ | `tinybird_config.py` | Python config alias |
463
+ | `tinybird.config.json` | JSON config (default for new projects) |
464
+ | `tinybird.json` | Legacy JSON config |
465
+
466
+ For Python configs, export one of:
467
+ - `config` dict
468
+ - `CONFIG` dict
469
+ - `default` dict
470
+ - `get_config()` returning a dict
471
+
472
+ Example:
473
+
474
+ ```python
475
+ # tinybird.config.py
476
+ config = {
477
+ "include": ["lib/*.py"],
478
+ "token": "${TINYBIRD_TOKEN}",
479
+ "base_url": "https://api.tinybird.co",
480
+ "dev_mode": "branch",
481
+ }
482
+ ```
483
+
484
+ ### Configuration Options
485
+
486
+ | Option | Type | Default | Description |
487
+ |--------|------|---------|-------------|
488
+ | `include` | `list[str]` | *required* | File paths or glob patterns for Python and raw datafiles |
489
+ | `token` | `str` | *required* | API token; supports `${ENV_VAR}` interpolation |
490
+ | `base_url` | `str` | `"https://api.tinybird.co"` | Tinybird API URL |
491
+ | `dev_mode` | `"branch"` \| `"local"` | `"branch"` | Development mode |
492
+
493
+ ### Local Development Mode
494
+
495
+ Use a local Tinybird container for development without affecting cloud workspaces:
496
+
497
+ 1. Start the local container:
498
+ ```bash
499
+ docker run -d -p 7181:7181 --name tinybird-local tinybirdco/tinybird-local:latest
500
+ ```
501
+
502
+ 2. Configure your project:
503
+ ```json
504
+ {
505
+ "dev_mode": "local"
506
+ }
507
+ ```
508
+
509
+ Or use CLI flag:
510
+ ```bash
511
+ tinybird dev --local
512
+ ```
513
+
514
+ ## Defining Resources
515
+
516
+ ### Connections
517
+
518
+ ```python
519
+ from tinybird_sdk import define_gcs_connection, define_kafka_connection, define_s3_connection, secret
520
+
521
+ events_kafka = define_kafka_connection(
522
+ "events_kafka",
523
+ {
524
+ "bootstrap_servers": "kafka.example.com:9092",
525
+ "security_protocol": "SASL_SSL",
526
+ "sasl_mechanism": "PLAIN",
527
+ "key": secret("KAFKA_KEY"),
528
+ "secret": secret("KAFKA_SECRET"),
529
+ },
530
+ )
531
+
532
+ landing_s3 = define_s3_connection(
533
+ "landing_s3",
534
+ {
535
+ "region": "us-east-1",
536
+ "arn": "arn:aws:iam::123456789012:role/tinybird-s3-access",
537
+ },
538
+ )
539
+
540
+ landing_gcs = define_gcs_connection(
541
+ "landing_gcs",
542
+ {
543
+ "service_account_credentials_json": secret("GCS_SERVICE_ACCOUNT_CREDENTIALS_JSON"),
544
+ },
545
+ )
546
+ ```
547
+
548
+ ### Datasources
549
+
550
+ ```python
551
+ from tinybird_sdk import define_datasource, engine, t
552
+
553
+ events = define_datasource(
554
+ "events",
555
+ {
556
+ "description": "Event tracking data",
557
+ "schema": {
558
+ "timestamp": t.date_time(),
559
+ "event_name": t.string().low_cardinality(),
560
+ "user_id": t.string().nullable(),
561
+ "properties": t.string(),
562
+ },
563
+ "engine": engine.merge_tree(
564
+ {
565
+ "sorting_key": ["event_name", "timestamp"],
566
+ "partition_key": "toYYYYMM(timestamp)",
567
+ "ttl": "timestamp + INTERVAL 90 DAY",
568
+ }
569
+ ),
570
+ },
571
+ )
572
+ ```
573
+
574
+ ### Endpoints (API pipes)
575
+
576
+ ```python
577
+ from tinybird_sdk import define_endpoint, node, p, t
578
+
579
+ top_events = define_endpoint(
580
+ "top_events",
581
+ {
582
+ "description": "Get the most frequent events",
583
+ "params": {
584
+ "start_date": p.date_time(),
585
+ "end_date": p.date_time(),
586
+ "limit": p.int32().optional(10),
587
+ },
588
+ "nodes": [
589
+ node(
590
+ {
591
+ "name": "aggregated",
592
+ "sql": """
593
+ SELECT event_name, count() AS event_count
594
+ FROM events
595
+ WHERE timestamp >= {{DateTime(start_date)}}
596
+ AND timestamp <= {{DateTime(end_date)}}
597
+ GROUP BY event_name
598
+ ORDER BY event_count DESC
599
+ LIMIT {{Int32(limit, 10)}}
600
+ """,
601
+ }
602
+ )
603
+ ],
604
+ "output": {
605
+ "event_name": t.string(),
606
+ "event_count": t.uint64(),
607
+ },
608
+ },
609
+ )
610
+ ```
611
+
612
+ ### Internal Pipes (not exposed as API)
613
+
614
+ ```python
615
+ from tinybird_sdk import define_pipe, node, p
616
+
617
+ filtered_events = define_pipe(
618
+ "filtered_events",
619
+ {
620
+ "description": "Filter events by date range",
621
+ "params": {
622
+ "start_date": p.date_time(),
623
+ "end_date": p.date_time(),
624
+ },
625
+ "nodes": [
626
+ node(
627
+ {
628
+ "name": "filtered",
629
+ "sql": """
630
+ SELECT * FROM events
631
+ WHERE timestamp >= {{DateTime(start_date)}}
632
+ AND timestamp <= {{DateTime(end_date)}}
633
+ """,
634
+ }
635
+ )
636
+ ],
637
+ },
638
+ )
639
+ ```
640
+
641
+ ### Materialized Views
642
+
643
+ ```python
644
+ from tinybird_sdk import define_datasource, define_materialized_view, engine, node, t
645
+
646
+ daily_stats = define_datasource(
647
+ "daily_stats",
648
+ {
649
+ "schema": {
650
+ "date": t.date(),
651
+ "pathname": t.string(),
652
+ "views": t.simple_aggregate_function("sum", t.uint64()),
653
+ "unique_sessions": t.aggregate_function("uniq", t.string()),
654
+ },
655
+ "engine": engine.aggregating_merge_tree({"sorting_key": ["date", "pathname"]}),
656
+ },
657
+ )
658
+
659
+ daily_stats_mv = define_materialized_view(
660
+ "daily_stats_mv",
661
+ {
662
+ "datasource": daily_stats,
663
+ "nodes": [
664
+ node(
665
+ {
666
+ "name": "aggregate",
667
+ "sql": """
668
+ SELECT
669
+ toDate(timestamp) AS date,
670
+ pathname,
671
+ count() AS views,
672
+ uniqState(session_id) AS unique_sessions
673
+ FROM page_views
674
+ GROUP BY date, pathname
675
+ """,
676
+ }
677
+ )
678
+ ],
679
+ },
680
+ )
681
+ ```
682
+
683
+ ### Copy Pipes
684
+
685
+ ```python
686
+ from tinybird_sdk import define_copy_pipe, node
687
+
688
+ # Scheduled copy pipe
689
+ daily_snapshot = define_copy_pipe(
690
+ "daily_snapshot",
691
+ {
692
+ "datasource": events,
693
+ "copy_schedule": "0 0 * * *",
694
+ "copy_mode": "append",
695
+ "nodes": [
696
+ node(
697
+ {
698
+ "name": "snapshot",
699
+ "sql": """
700
+ SELECT today() AS snapshot_date, event_name, count() AS events
701
+ FROM events
702
+ WHERE toDate(timestamp) = today() - 1
703
+ GROUP BY event_name
704
+ """,
705
+ }
706
+ )
707
+ ],
708
+ },
709
+ )
710
+
711
+ # On-demand copy pipe
712
+ manual_report = define_copy_pipe(
713
+ "manual_report",
714
+ {
715
+ "datasource": events,
716
+ "copy_schedule": "@on-demand",
717
+ "copy_mode": "replace",
718
+ "nodes": [
719
+ node(
720
+ {
721
+ "name": "report",
722
+ "sql": "SELECT * FROM events WHERE timestamp >= now() - interval 7 day",
723
+ }
724
+ )
725
+ ],
726
+ },
727
+ )
728
+ ```
729
+
730
+ ### Sink Pipes
731
+
732
+ Use sink pipes to publish query results to external systems.
733
+ The SDK supports Kafka and S3 sinks.
734
+
735
+ ```python
736
+ from tinybird_sdk import define_sink_pipe, node
737
+
738
+ # Kafka sink
739
+ kafka_events_sink = define_sink_pipe(
740
+ "kafka_events_sink",
741
+ {
742
+ "sink": {
743
+ "connection": events_kafka,
744
+ "topic": "events_export",
745
+ "schedule": "@on-demand",
746
+ },
747
+ "nodes": [
748
+ node(
749
+ {
750
+ "name": "publish",
751
+ "sql": "SELECT timestamp, payload FROM kafka_events",
752
+ }
753
+ )
754
+ ],
755
+ },
756
+ )
757
+
758
+ # S3 sink
759
+ s3_events_sink = define_sink_pipe(
760
+ "s3_events_sink",
761
+ {
762
+ "sink": {
763
+ "connection": landing_s3,
764
+ "bucket_uri": "s3://my-bucket/exports/",
765
+ "file_template": "events_{date}",
766
+ "format": "csv",
767
+ "schedule": "@once",
768
+ "strategy": "create_new",
769
+ "compression": "gzip",
770
+ },
771
+ "nodes": [
772
+ node(
773
+ {
774
+ "name": "export",
775
+ "sql": "SELECT timestamp, session_id FROM s3_landing",
776
+ }
777
+ )
778
+ ],
779
+ },
780
+ )
781
+ ```
782
+
783
+ ### Static Tokens
784
+
785
+ ```python
786
+ from tinybird_sdk import define_datasource, define_endpoint, define_token, node, t
787
+
788
+ app_token = define_token("app_read")
789
+ ingest_token = define_token("ingest_token")
790
+
791
+ events = define_datasource(
792
+ "events",
793
+ {
794
+ "schema": {
795
+ "timestamp": t.date_time(),
796
+ "event_name": t.string(),
797
+ },
798
+ "tokens": [
799
+ {"token": app_token, "scope": "READ"},
800
+ {"token": ingest_token, "scope": "APPEND"},
801
+ ],
802
+ },
803
+ )
804
+
805
+ top_events = define_endpoint(
806
+ "top_events",
807
+ {
808
+ "nodes": [node({"name": "endpoint", "sql": "SELECT * FROM events LIMIT 10"})],
809
+ "output": {"timestamp": t.date_time(), "event_name": t.string()},
810
+ "tokens": [{"token": app_token, "scope": "READ"}],
811
+ },
812
+ )
813
+ ```
814
+
815
+ ## Type Validators
816
+
817
+ Use `t.*` to define column types:
818
+
819
+ ```python
820
+ from tinybird_sdk import t
821
+
822
+ schema = {
823
+ # Strings
824
+ "name": t.string(),
825
+ "id": t.uuid(),
826
+ "code": t.fixed_string(3),
827
+
828
+ # Numbers
829
+ "count": t.int32(),
830
+ "amount": t.float64(),
831
+ "big_number": t.uint64(),
832
+ "price": t.decimal(10, 2),
833
+
834
+ # Date/Time
835
+ "created_at": t.date_time(),
836
+ "updated_at": t.date_time64(3),
837
+ "birth_date": t.date(),
838
+
839
+ # Boolean
840
+ "is_active": t.bool(),
841
+
842
+ # Complex types
843
+ "tags": t.array(t.string()),
844
+ "metadata": t.map(t.string(), t.string()),
845
+
846
+ # Aggregate functions
847
+ "total": t.simple_aggregate_function("sum", t.uint64()),
848
+ "unique_users": t.aggregate_function("uniq", t.string()),
849
+
850
+ # Modifiers
851
+ "optional_field": t.string().nullable(),
852
+ "category": t.string().low_cardinality(),
853
+ "status": t.string().default("pending"),
854
+ }
855
+ ```
856
+
857
+ ## Parameter Validators
858
+
859
+ Use `p.*` to define query parameters:
860
+
861
+ ```python
862
+ from tinybird_sdk import p
863
+
864
+ params = {
865
+ "start_date": p.date_time(),
866
+ "user_id": p.string(),
867
+
868
+ "limit": p.int32().optional(10),
869
+ "offset": p.int32().optional(0),
870
+
871
+ "status": p.string().optional("active").describe("Filter by status"),
872
+ }
873
+ ```
874
+
875
+ ## Engine Configurations
876
+
877
+ ```python
878
+ from tinybird_sdk import engine
879
+
880
+ engine.merge_tree(
881
+ {
882
+ "sorting_key": ["user_id", "timestamp"],
883
+ "partition_key": "toYYYYMM(timestamp)",
884
+ "ttl": "timestamp + INTERVAL 90 DAY",
885
+ }
886
+ )
887
+
888
+ engine.replacing_merge_tree(
889
+ {
890
+ "sorting_key": ["id"],
891
+ "ver": "updated_at",
892
+ }
893
+ )
894
+
895
+ engine.summing_merge_tree(
896
+ {
897
+ "sorting_key": ["date", "category"],
898
+ "columns": ["count", "total"],
899
+ }
900
+ )
901
+
902
+ engine.aggregating_merge_tree(
903
+ {
904
+ "sorting_key": ["date"],
905
+ }
906
+ )
907
+ ```
908
+
909
+ ## Python App Integration
910
+
911
+ For Python web apps (FastAPI, Django, Flask), keep Tinybird definitions and client in a dedicated module and import that module from your app services.
912
+
913
+ The CLI automatically loads `.env.local` and `.env` files in project root when resolving configuration.
914
+
915
+ ## Schema Inference Helpers
916
+
917
+ The `tinybird_sdk.infer` module can inspect datasource and pipe definitions:
918
+
919
+ ```python
920
+ from tinybird_sdk.infer import infer_output_schema, infer_params_schema, infer_row_schema
921
+
922
+ row_schema = infer_row_schema(page_views)
923
+ params_schema = infer_params_schema(top_pages)
924
+ output_schema = infer_output_schema(top_pages)
925
+ ```
926
+
927
+ ## License
928
+
929
+ MIT