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.
- tinybird_sdk-0.1.0/PKG-INFO +929 -0
- tinybird_sdk-0.1.0/README.md +919 -0
- tinybird_sdk-0.1.0/pyproject.toml +29 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/__init__.py +99 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/_http.py +176 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/api/__init__.py +78 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/api/api.py +492 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/api/branches.py +162 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/api/build.py +121 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/api/dashboard.py +47 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/api/deploy.py +232 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/api/fetcher.py +21 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/api/local.py +154 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/api/regions.py +34 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/api/resources.py +417 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/api/tokens.py +67 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/api/workspaces.py +45 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/__init__.py +62 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/auth.py +142 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/branch_store.py +94 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/__init__.py +34 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/branch.py +103 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/build.py +185 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/clear.py +67 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/deploy.py +79 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/dev.py +97 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/generate.py +131 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/info.py +93 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/init.py +154 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/login.py +56 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/migrate.py +46 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/open_dashboard.py +65 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/preview.py +200 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/commands/pull.py +121 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/config.py +244 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/config_loader.py +95 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/config_types.py +15 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/env.py +49 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/git.py +80 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/index.py +92 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/output.py +205 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/region_selector.py +72 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/utils/__init__.py +23 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/utils/package_manager.py +154 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/cli/utils/schema_validation.py +179 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/client/__init__.py +19 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/client/base.py +230 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/client/preview.py +111 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/client/tokens.py +40 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/client/types.py +128 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/codegen/__init__.py +28 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/codegen/index.py +198 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/codegen/type_mapper.py +147 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/codegen/utils.py +156 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/generator/__init__.py +45 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/generator/client.py +93 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/generator/connection.py +80 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/generator/datasource.py +193 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/generator/include_paths.py +107 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/generator/index.py +148 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/generator/loader.py +255 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/generator/pipe.py +135 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/infer/__init__.py +15 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/infer/index.py +50 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/__init__.py +55 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/discovery.py +140 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/emit_ts.py +494 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/parse.py +16 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/parse_connection.py +213 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/parse_datasource.py +505 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/parse_pipe.py +803 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/parser_utils.py +158 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/runner.py +317 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/migrate/types.py +223 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/py.typed +0 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/schema/__init__.py +100 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/schema/connection.py +117 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/schema/datasource.py +187 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/schema/engines.py +100 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/schema/params.py +122 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/schema/pipe.py +427 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/schema/project.py +230 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/schema/secret.py +11 -0
- tinybird_sdk-0.1.0/src/tinybird_sdk/schema/token.py +28 -0
- 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
|