tinybird 0.0.1.dev103__py3-none-any.whl → 0.0.1.dev105__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.
tinybird/sql_template.py CHANGED
@@ -2427,6 +2427,20 @@ def render_template_with_secrets(name: str, content: str, secrets: Optional[Dict
2427
2427
  ... )
2428
2428
  'KAFKA_BOOTSTRAP_SERVERS localhost:9092'
2429
2429
 
2430
+ >>> render_template_with_secrets(
2431
+ ... "my_kafka_connection",
2432
+ ... "KAFKA_BOOTSTRAP_SERVERS {{ tb_secret('MISSING_SECRET', '') }}",
2433
+ ... secrets = {}
2434
+ ... )
2435
+ 'KAFKA_BOOTSTRAP_SERVERS ""'
2436
+
2437
+ >>> render_template_with_secrets(
2438
+ ... "my_kafka_connection",
2439
+ ... "KAFKA_BOOTSTRAP_SERVERS {{ tb_secret('MISSING_SECRET', 0) }}",
2440
+ ... secrets = {}
2441
+ ... )
2442
+ 'KAFKA_BOOTSTRAP_SERVERS 0'
2443
+
2430
2444
  >>> render_template_with_secrets(
2431
2445
  ... "my_kafka_connection",
2432
2446
  ... "KAFKA_BOOTSTRAP_SERVERS {{ tb_secret('MISSING_SECRET') }}",
@@ -2453,8 +2467,13 @@ def render_template_with_secrets(name: str, content: str, secrets: Optional[Dict
2453
2467
  SQLTemplateException: If the secret is not found and no default is provided
2454
2468
  """
2455
2469
  if secret_name in secrets:
2456
- return secrets[secret_name]
2470
+ value = secrets[secret_name]
2471
+ if isinstance(value, str) and len(value) == 0:
2472
+ return '""'
2473
+ return value
2457
2474
  elif default is not None:
2475
+ if isinstance(default, str) and len(default) == 0:
2476
+ return '""'
2458
2477
  return default
2459
2478
  else:
2460
2479
  raise SQLTemplateException(
@@ -2462,7 +2481,7 @@ def render_template_with_secrets(name: str, content: str, secrets: Optional[Dict
2462
2481
  )
2463
2482
 
2464
2483
  # Create the template
2465
- t = Template(content, name=name)
2484
+ t = Template(content, name=name, autoescape=None)
2466
2485
 
2467
2486
  try:
2468
2487
  # Create namespace with our tb_secret function
tinybird/tb/__cli__.py CHANGED
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
4
4
  __url__ = 'https://www.tinybird.co/docs/cli/introduction.html'
5
5
  __author__ = 'Tinybird'
6
6
  __author_email__ = 'support@tinybird.co'
7
- __version__ = '0.0.1.dev103'
8
- __revision__ = 'e2e3b60'
7
+ __version__ = '0.0.1.dev105'
8
+ __revision__ = '43fbce5'
@@ -81,8 +81,6 @@ SUPPORTED_FORMATS = ["csv", "ndjson", "json", "parquet"]
81
81
  OLDEST_ROLLBACK = "oldest_rollback"
82
82
  MAIN_BRANCH = "main"
83
83
 
84
- CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
85
-
86
84
 
87
85
  def obfuscate_token(value: Optional[str]) -> Optional[str]:
88
86
  if not value:
@@ -2178,36 +2176,24 @@ async def ask_for_organization(
2178
2176
 
2179
2177
  if organization_id:
2180
2178
  if organizations and len(organizations) > 0:
2181
- organization = next(
2182
- (org for org in organizations if org.get("id") == organization_id), None
2183
- )
2179
+ organization = next((org for org in organizations if org.get("id") == organization_id), None)
2184
2180
  if not organization:
2185
- raise CLIException(
2186
- FeedbackManager.error_organization_not_found(
2187
- organization_id=organization_id
2188
- )
2189
- )
2181
+ raise CLIException(FeedbackManager.error_organization_not_found(organization_id=organization_id))
2190
2182
  organization_name = organization.get("name")
2191
2183
  return organization_id, organization_name
2192
2184
 
2193
2185
  if organizations is None or len(organizations) == 0:
2194
2186
  organization_name = await ask_for_organization_name(config)
2195
2187
  user_token = await get_user_token(config, user_token)
2196
- organization = await create_organization_and_add_workspaces(
2197
- config, organization_name, user_token
2198
- )
2188
+ organization = await create_organization_and_add_workspaces(config, organization_name, user_token)
2199
2189
  organization_id = organization.get("id")
2200
2190
  else:
2201
2191
  if len(organizations) == 1:
2202
2192
  organization_name = organizations[0]["name"]
2203
2193
  organization_id = organizations[0]["id"]
2204
2194
  else:
2205
- sorted_organizations = sort_organizations_by_user(
2206
- organizations, user_email=user_email
2207
- )
2208
- current_organization = await ask_for_organization_interactively(
2209
- sorted_organizations
2210
- )
2195
+ sorted_organizations = sort_organizations_by_user(organizations, user_email=user_email)
2196
+ current_organization = await ask_for_organization_interactively(sorted_organizations)
2211
2197
  if current_organization:
2212
2198
  organization_id = current_organization.get("id")
2213
2199
  organization_name = current_organization.get("name")
@@ -1241,6 +1241,13 @@ def parse(
1241
1241
 
1242
1242
  return _f
1243
1243
 
1244
+ def kafka_key_avro_deserialization(*args: str, **kwargs: Any):
1245
+ raise DatafileSyntaxError(
1246
+ f'{kwargs["cmd"].upper()} has been deprecated. Use "KAFKA_KEY_FORMAT avro" instead',
1247
+ lineno=kwargs["lineno"],
1248
+ pos=1,
1249
+ )
1250
+
1244
1251
  @deprecated
1245
1252
  def sources(x: str, **kwargs: Any) -> None:
1246
1253
  pass # Deprecated
@@ -1459,7 +1466,7 @@ def parse(
1459
1466
  "kafka_store_raw_value": assign_var("kafka_store_raw_value"),
1460
1467
  "kafka_store_headers": assign_var("kafka_store_headers"),
1461
1468
  "kafka_store_binary_headers": assign_var("kafka_store_binary_headers"),
1462
- "kafka_key_avro_deserialization": assign_var("kafka_key_avro_deserialization"),
1469
+ "kafka_key_avro_deserialization": kafka_key_avro_deserialization,
1463
1470
  "kafka_ssl_ca_pem": assign_var("kafka_ssl_ca_pem"),
1464
1471
  "kafka_security_protocol": assign_var("kafka_security_protocol"),
1465
1472
  "kafka_sasl_mechanism": assign_var("kafka_sasl_mechanism"),
@@ -19,6 +19,7 @@ from tinybird.tb.modules.project import Project
19
19
  def api_fetch(url: str, headers: dict) -> dict:
20
20
  r = requests.get(url, headers=headers)
21
21
  if r.status_code == 200:
22
+ logging.debug(json.dumps(r.json(), indent=2))
22
23
  return r.json()
23
24
  # Try to parse and print the error from the response
24
25
  try:
@@ -32,13 +33,33 @@ def api_fetch(url: str, headers: dict) -> dict:
32
33
  sys.exit(1)
33
34
 
34
35
 
36
+ def api_post(
37
+ url: str,
38
+ headers: dict,
39
+ files: Optional[list] = None,
40
+ params: Optional[dict] = None,
41
+ ) -> dict:
42
+ r = requests.post(url, headers=headers, files=files, params=params)
43
+ if r.status_code == 200:
44
+ logging.debug(json.dumps(r.json(), indent=2))
45
+ return r.json()
46
+ # Try to parse and print the error from the response
47
+ try:
48
+ result = r.json()
49
+ logging.debug(json.dumps(result, indent=2))
50
+ error = result.get("error")
51
+ click.echo(FeedbackManager.error(message=f"Error: {error}"))
52
+ sys.exit(1)
53
+ except Exception:
54
+ click.echo(FeedbackManager.error(message="Error parsing response from API"))
55
+ sys.exit(1)
56
+
57
+
35
58
  # TODO(eclbg): This logic should be in the server, and there should be a dedicated endpoint for promoting a deployment
36
59
  # potato
37
60
  def promote_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
38
61
  TINYBIRD_API_URL = f"{host}/v1/deployments"
39
- r = requests.get(TINYBIRD_API_URL, headers=headers)
40
- result = r.json()
41
- logging.debug(json.dumps(result, indent=2))
62
+ result = api_fetch(TINYBIRD_API_URL, headers)
42
63
 
43
64
  deployments = result.get("deployments")
44
65
  if not deployments:
@@ -64,12 +85,7 @@ def promote_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
64
85
  click.echo(FeedbackManager.success(message="Setting candidate deployment as live"))
65
86
 
66
87
  TINYBIRD_API_URL = f"{host}/v1/deployments/{candidate_deployment.get('id')}/set-live"
67
- r = requests.post(TINYBIRD_API_URL, headers=headers)
68
- result = r.json()
69
- logging.debug(json.dumps(result, indent=2))
70
- if result.get("error"):
71
- click.echo(FeedbackManager.error(message=result.get("error")))
72
- sys.exit(1)
88
+ result = api_post(TINYBIRD_API_URL, headers=headers)
73
89
 
74
90
  click.echo(FeedbackManager.success(message="Removing old deployment"))
75
91
 
@@ -86,9 +102,7 @@ def promote_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
86
102
  if wait:
87
103
  while True:
88
104
  TINYBIRD_API_URL = f"{host}/v1/deployments/{last_deployment.get('id')}"
89
- r = requests.get(TINYBIRD_API_URL, headers=headers)
90
- result = r.json()
91
- logging.debug(json.dumps(result, indent=2))
105
+ result = api_fetch(TINYBIRD_API_URL, headers=headers)
92
106
 
93
107
  last_deployment = result.get("deployment")
94
108
  if last_deployment.get("status") == "deleted":
@@ -98,13 +112,11 @@ def promote_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
98
112
  time.sleep(5)
99
113
 
100
114
 
101
- # TODO(eclbg): This logic should be in the server, and there should be a dedicated endpoint for rolling back a
115
+ # TODO(eclbg): This logic should be in the server, and there should be a dedicated endpoint for discarding a
102
116
  # deployment
103
- def rollback_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
117
+ def discard_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
104
118
  TINYBIRD_API_URL = f"{host}/v1/deployments"
105
- r = requests.get(TINYBIRD_API_URL, headers=headers)
106
- result = r.json()
107
- logging.debug(json.dumps(result, indent=2))
119
+ result = api_fetch(TINYBIRD_API_URL, headers=headers)
108
120
 
109
121
  deployments = result.get("deployments")
110
122
  if not deployments:
@@ -130,12 +142,7 @@ def rollback_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
130
142
  click.echo(FeedbackManager.success(message="Promoting previous deployment"))
131
143
 
132
144
  TINYBIRD_API_URL = f"{host}/v1/deployments/{previous_deployment.get('id')}/set-live"
133
- r = requests.post(TINYBIRD_API_URL, headers=headers)
134
- result = r.json()
135
- logging.debug(json.dumps(result, indent=2))
136
- if result.get("error"):
137
- click.echo(FeedbackManager.error(message=result.get("error")))
138
- sys.exit(1)
145
+ result = api_post(TINYBIRD_API_URL, headers=headers)
139
146
 
140
147
  click.echo(FeedbackManager.success(message="Removing current deployment"))
141
148
 
@@ -147,18 +154,16 @@ def rollback_deployment(host: Optional[str], headers: dict, wait: bool) -> None:
147
154
  click.echo(FeedbackManager.error(message=result.get("error")))
148
155
  sys.exit(1)
149
156
 
150
- click.echo(FeedbackManager.success(message="Deployment rollback successfully started"))
157
+ click.echo(FeedbackManager.success(message="Discard process successfully started"))
151
158
 
152
159
  if wait:
153
160
  while True:
154
161
  TINYBIRD_API_URL = f"{host}/v1/deployments/{current_deployment.get('id')}"
155
- r = requests.get(TINYBIRD_API_URL, headers=headers)
156
- result = r.json()
157
- logging.debug(json.dumps(result, indent=2))
162
+ result = api_fetch(TINYBIRD_API_URL, headers)
158
163
 
159
164
  current_deployment = result.get("deployment")
160
165
  if current_deployment.get("status") == "deleted":
161
- click.echo(FeedbackManager.success(message="Deployment rolled back successfully"))
166
+ click.echo(FeedbackManager.success(message="Discard process successfully completed"))
162
167
  break
163
168
  time.sleep(5)
164
169
 
@@ -219,7 +224,6 @@ def deployment_ls(ctx: click.Context) -> None:
219
224
  url = f"{client.host}/v1/deployments"
220
225
 
221
226
  result = api_fetch(url, HEADERS)
222
- logging.debug(json.dumps(result, indent=2))
223
227
 
224
228
  status_map = {"data_ready": "Ready", "failed": "Failed"}
225
229
  columns = ["ID", "Status", "Created at", "Live"]
@@ -260,7 +264,7 @@ def deployment_promote(ctx: click.Context, wait: bool) -> None:
260
264
  promote_deployment(client.host, HEADERS, wait=wait)
261
265
 
262
266
 
263
- @deployment_group.command(name="rollback")
267
+ @deployment_group.command(name="discard")
264
268
  @click.pass_context
265
269
  @click.option(
266
270
  "--wait/--no-wait",
@@ -268,16 +272,16 @@ def deployment_promote(ctx: click.Context, wait: bool) -> None:
268
272
  default=False,
269
273
  help="Wait for deploy to finish. Disabled by default.",
270
274
  )
271
- def deployment_rollback(ctx: click.Context, wait: bool) -> None:
275
+ def deployment_discard(ctx: click.Context, wait: bool) -> None:
272
276
  """
273
- Rollback to the previous deployment.
277
+ Discard the current deployment.
274
278
  """
275
279
  client = ctx.ensure_object(dict)["client"]
276
280
 
277
281
  TINYBIRD_API_KEY = client.token
278
282
  HEADERS = {"Authorization": f"Bearer {TINYBIRD_API_KEY}"}
279
283
 
280
- rollback_deployment(client.host, HEADERS, wait=wait)
284
+ discard_deployment(client.host, HEADERS, wait=wait)
281
285
 
282
286
 
283
287
  @cli.command(name="deploy", hidden=True)
@@ -291,7 +295,7 @@ def deployment_rollback(ctx: click.Context, wait: bool) -> None:
291
295
  "--auto/--no-auto",
292
296
  is_flag=True,
293
297
  default=True,
294
- help="Auto-promote the deployment. Only works if --wait is enabled. Disabled by default.",
298
+ help="Auto-promote or auto-discard the deployment. Only works if --wait is enabled. Disabled by default.",
295
299
  )
296
300
  @click.option(
297
301
  "--check",
@@ -354,13 +358,13 @@ def create_deployment(
354
358
  params["check"] = "true"
355
359
  if allow_destructive_operations:
356
360
  params["allow_destructive_operations"] = "true"
357
- r = requests.post(TINYBIRD_API_URL, files=files, headers=HEADERS, params=params)
358
- result = r.json()
359
- logging.debug(json.dumps(result, indent=2))
361
+
362
+ result = api_post(TINYBIRD_API_URL, headers=HEADERS, files=files, params=params)
360
363
 
361
364
  print_changes(result, project)
362
365
 
363
- feedback = result.get("deployment", {}).get("feedback", [])
366
+ deployment = result.get("deployment", {})
367
+ feedback = deployment.get("feedback", [])
364
368
  for f in feedback:
365
369
  if f.get("level", "").upper() == "ERROR":
366
370
  feedback_func = FeedbackManager.error
@@ -372,7 +376,7 @@ def create_deployment(
372
376
  resource_bit = f"{resource}: " if resource else ""
373
377
  click.echo(feedback_func(message=f"{feedback_icon}{f.get('level')}: {resource_bit}{f.get('message')}"))
374
378
 
375
- deploy_errors = result.get("deployment", {}).get("errors")
379
+ deploy_errors = deployment.get("errors")
376
380
  for deploy_error in deploy_errors:
377
381
  if deploy_error.get("filename", None):
378
382
  click.echo(
@@ -380,19 +384,21 @@ def create_deployment(
380
384
  )
381
385
  else:
382
386
  click.echo(FeedbackManager.error(message=f"{deploy_error.get('error')}"))
387
+ click.echo() # For spacing
383
388
 
384
389
  status = result.get("result")
385
390
  if check:
386
391
  if status == "success":
387
392
  click.echo(FeedbackManager.success(message="\n✓ Deployment is valid"))
388
393
  sys.exit(0)
394
+ elif status == "no_changes":
395
+ sys.exit(0)
389
396
 
390
397
  click.echo(FeedbackManager.error(message="\n✗ Deployment is not valid"))
391
398
  sys.exit(1)
392
399
 
393
400
  status = result.get("result")
394
401
  if status == "success":
395
- deployment = result.get("deployment", {})
396
402
  # TODO: This is a hack to show the url in the case of region is public. The URL should be returned by the API
397
403
  if client.host == "https://api.europe-west2.gcp.tinybird.co":
398
404
  click.echo(
@@ -406,10 +412,14 @@ def create_deployment(
406
412
  click.echo(FeedbackManager.info(message="\n✓ Deployment submitted successfully"))
407
413
  else:
408
414
  click.echo(FeedbackManager.success(message="\n✓ Deployment submitted successfully"))
415
+ elif status == "no_changes":
416
+ click.echo(FeedbackManager.highlight(message="Not deploying. No changes."))
417
+ sys.exit(0)
409
418
  elif status == "failed":
410
419
  click.echo(FeedbackManager.error(message="Deployment failed"))
420
+ sys.exit(1)
411
421
  else:
412
- click.echo(FeedbackManager.error(message=f"Unknown build result {status}"))
422
+ click.echo(FeedbackManager.error(message=f"Unknown deployment result {status}"))
413
423
  except Exception as e:
414
424
  click.echo(FeedbackManager.error_exception(error=e))
415
425
  finally:
@@ -435,7 +445,7 @@ def create_deployment(
435
445
 
436
446
  if auto:
437
447
  click.echo(FeedbackManager.error(message="Rolling back deployment"))
438
- rollback_deployment(client.host, HEADERS, wait=wait)
448
+ discard_deployment(client.host, HEADERS, wait=wait)
439
449
  sys.exit(1)
440
450
 
441
451
  if deployment.get("status") == "data_ready":
@@ -463,7 +473,7 @@ def print_changes(result: dict, project: Project) -> None:
463
473
  resources.append(["new", p, project.get_resource_path(p, "pipe")])
464
474
 
465
475
  for dc in deployment.get("new_data_connector_names", []):
466
- resources.append(["new", dc, project.get_resource_path(dc, "data_connector")])
476
+ resources.append(["new", dc, project.get_resource_path(dc, "connection")])
467
477
 
468
478
  for ds in deployment.get("changed_datasource_names", []):
469
479
  resources.append(["modified", ds, project.get_resource_path(ds, "datasource")])
@@ -472,7 +482,7 @@ def print_changes(result: dict, project: Project) -> None:
472
482
  resources.append(["modified", p, project.get_resource_path(p, "pipe")])
473
483
 
474
484
  for dc in deployment.get("changed_data_connector_names", []):
475
- resources.append(["modified", dc, project.get_resource_path(dc, "data_connector")])
485
+ resources.append(["modified", dc, project.get_resource_path(dc, "connection")])
476
486
 
477
487
  for ds in deployment.get("deleted_datasource_names", []):
478
488
  resources.append(["deleted", ds, project.get_resource_path(ds, "datasource")])
@@ -481,7 +491,7 @@ def print_changes(result: dict, project: Project) -> None:
481
491
  resources.append(["deleted", p, project.get_resource_path(p, "pipe")])
482
492
 
483
493
  for dc in deployment.get("deleted_data_connector_names", []):
484
- resources.append(["deleted", dc, project.get_resource_path(dc, "data_connector")])
494
+ resources.append(["deleted", dc, project.get_resource_path(dc, "connection")])
485
495
 
486
496
  for token_change in deployment.get("token_changes", []):
487
497
  token_name = token_change.get("token_name")
@@ -1,5 +1,7 @@
1
+ import asyncio
1
2
  import json
2
3
  import subprocess
4
+ import sys
3
5
  import time
4
6
  import uuid
5
7
  from pathlib import Path
@@ -15,7 +17,7 @@ from tinybird.tb.modules.common import coro, echo_safe_humanfriendly_tables_form
15
17
  from tinybird.tb.modules.config import CLIConfig
16
18
  from tinybird.tb.modules.feedback_manager import FeedbackManager
17
19
 
18
- from .common import CONTEXT_SETTINGS, ask_for_organization, get_organizations_by_user
20
+ from .common import ask_for_organization, get_organizations_by_user
19
21
 
20
22
  K8S_YML = """
21
23
  ---
@@ -226,13 +228,9 @@ class Infrastructure:
226
228
  async def get_organizations_info(self, config: CLIConfig):
227
229
  self.orgs = await get_organizations_by_user(config)
228
230
 
229
- async def create_infra(
230
- self, name: str, host: str, organization_id: str
231
- ) -> Dict[str, Any]:
231
+ async def create_infra(self, name: str, host: str, organization_id: str) -> Dict[str, Any]:
232
232
  """Create a new infrastructure."""
233
- infra = await self.client.infra_create(
234
- organization_id=organization_id, name=name, host=host
235
- )
233
+ infra = await self.client.infra_create(organization_id=organization_id, name=name, host=host)
236
234
  return infra
237
235
 
238
236
  async def list_infras(self) -> None:
@@ -253,9 +251,7 @@ class Infrastructure:
253
251
  organization = infra["organization"]
254
252
 
255
253
  table_human_readable.append((name, host, organization))
256
- table_machine_readable.append(
257
- {"name": name, "host": host, "organization": organization}
258
- )
254
+ table_machine_readable.append({"name": name, "host": host, "organization": organization})
259
255
 
260
256
  click.echo(FeedbackManager.info(message="\n** Infras:"))
261
257
  echo_safe_humanfriendly_tables_format_smart_table(table_human_readable, column_names=columns)
@@ -269,17 +265,13 @@ class Infrastructure:
269
265
  if not infra:
270
266
  raise CLIException(f"Infrastructure '{name}' not found")
271
267
  await self.client.infra_delete(infra["id"], infra["organization_id"])
272
- click.echo(
273
- FeedbackManager.success(message=f"\n✓ Infrastructure '{name}' deleted")
274
- )
268
+ click.echo(FeedbackManager.success(message=f"\n✓ Infrastructure '{name}' deleted"))
275
269
  except Exception as e:
276
270
  click.echo(FeedbackManager.error(message=f"✗ Error: {e}"))
277
271
 
278
272
  async def update(self, infra_name: str, name: str, host: str):
279
273
  infras_list = await self.get_infra_list()
280
- infra = next(
281
- (infra for infra in infras_list if infra["name"] == infra_name), None
282
- )
274
+ infra = next((infra for infra in infras_list if infra["name"] == infra_name), None)
283
275
  if not infra:
284
276
  return None
285
277
  await self.client.infra_update(
@@ -312,30 +304,25 @@ class Infrastructure:
312
304
  all_infras.append(infra)
313
305
  except Exception as e:
314
306
  click.echo(
315
- FeedbackManager.warning(
316
- message=f"Could not fetch infras for organization {org_name}: {str(e)}"
317
- )
307
+ FeedbackManager.warning(message=f"Could not fetch infras for organization {org_name}: {str(e)}")
318
308
  )
319
309
  continue
320
310
  return all_infras
321
311
  except Exception as e:
322
- click.echo(
323
- FeedbackManager.error(
324
- message=f"Failed to list infrastructures: {str(e)}"
325
- )
326
- )
312
+ click.echo(FeedbackManager.error(message=f"Failed to list infrastructures: {str(e)}"))
327
313
  return []
328
314
 
329
315
 
330
- @cli.group(context_settings=CONTEXT_SETTINGS, hidden=True)
316
+ @cli.group(hidden=True)
331
317
  @click.pass_context
332
- @coro
333
- async def infra(ctx: Context) -> None:
318
+ def infra(ctx: Context) -> None:
334
319
  """Infra commands."""
320
+ if "--help" in sys.argv or "-h" in sys.argv:
321
+ return
335
322
  client: TinyB = ctx.ensure_object(dict)["client"]
336
323
  config = CLIConfig.get_project_config()
337
324
  infra = Infrastructure(client)
338
- await infra.get_organizations_info(config)
325
+ asyncio.run(infra.get_organizations_info(config))
339
326
  ctx.ensure_object(dict)["infra"] = infra
340
327
 
341
328
 
@@ -732,24 +719,28 @@ async def infra_list(ctx: click.Context):
732
719
  @click.option("--host", type=str, help="Host for the self-managed region")
733
720
  @click.option("--organization-id", type=str, help="Organization ID for the self-managed region")
734
721
  @click.pass_context
735
- @coro
736
- async def infra_create(ctx: click.Context, name: str, host: str, organization_id: Optional[str] = None):
722
+ def infra_add(ctx: click.Context, name: str, host: Optional[str] = None, organization_id: Optional[str] = None):
737
723
  """Creates a new self-managed region from an existing infrastructure URL."""
738
724
  infra: Infrastructure = ctx.ensure_object(dict)["infra"]
739
725
 
740
- organization_id, organization_name = await ask_for_organization(
741
- infra.orgs, organization_id
742
- )
726
+ organization_id, organization_name = asyncio.run(ask_for_organization(infra.orgs, organization_id))
743
727
  if not organization_id:
744
728
  return
745
729
 
746
730
  name = name or click.prompt("Enter name", type=str)
747
- host = host or click.prompt("Enter host", type=str)
731
+ host = host or click.prompt(
732
+ "Enter host URL (e.g., https://tinybird.example.com) (leave empty for None)",
733
+ type=str,
734
+ default="",
735
+ show_default=False,
736
+ )
748
737
 
749
738
  click.echo(FeedbackManager.highlight(message=f"» Adding self-managed region '{name}' in Tinybird..."))
750
- new_infra = await infra.create_infra(name, host, organization_id)
739
+ new_infra = asyncio.run(infra.create_infra(name, host, organization_id))
751
740
  infra_token = new_infra["token"]
752
- click.echo(FeedbackManager.success(message=f"\n✓ Self-managed region '{name}' added in '{organization_name}' Organization"))
741
+ click.echo(
742
+ FeedbackManager.success(message=f"\n✓ Self-managed region '{name}' added in '{organization_name}' Organization")
743
+ )
753
744
 
754
745
  # Get CLI config to access workspace and user information
755
746
  cli_config = CLIConfig.get_project_config()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev103
3
+ Version: 0.0.1.dev105
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -8,31 +8,31 @@ tinybird/feedback_manager.py,sha256=a_ZhFX2zcB7vRknIcmHKMdQbb0c7TqlTBQ_5hPuWh88,
8
8
  tinybird/git_settings.py,sha256=Sw_8rGmribEFJ4Z_6idrVytxpFYk7ez8ei0qHULzs3E,3934
9
9
  tinybird/prompts.py,sha256=RgV1B7-b6-1xXStNlhKikYSCG1WNaddDVeSp8hSgBlE,33753
10
10
  tinybird/sql.py,sha256=J35bhdpuu84HW2tiLp-cs_nzkRwPhiy1yPcFhcWMCR4,46248
11
- tinybird/sql_template.py,sha256=VH8io4n5eP2z6TEw111d8hcA9FKQerFjprKKCW2MODw,99127
11
+ tinybird/sql_template.py,sha256=mK0yeRFctbXTAu0VNMjIzoFBJoh9PoniAVgEatA5SG4,99832
12
12
  tinybird/sql_template_fmt.py,sha256=KUHdj5rYCYm_rKKdXYSJAE9vIyXUQLB0YSZnUXHeBlY,10196
13
13
  tinybird/sql_toolset.py,sha256=KORVbNAUTfW1qo3U9oe7Z59xQ0QMsFhB0ji3HzY2JVo,15324
14
14
  tinybird/syncasync.py,sha256=IPnOx6lMbf9SNddN1eBtssg8vCLHMt76SuZ6YNYm-Yk,27761
15
15
  tinybird/tornado_template.py,sha256=jjNVDMnkYFWXflmT8KU_Ssbo5vR8KQq3EJMk5vYgXRw,41959
16
16
  tinybird/ch_utils/constants.py,sha256=aYvg2C_WxYWsnqPdZB1ZFoIr8ZY-XjUXYyHKE9Ansj0,3890
17
17
  tinybird/ch_utils/engine.py,sha256=BZuPM7MFS7vaEKK5tOMR2bwSAgJudPrJt27uVEwZmTY,40512
18
- tinybird/tb/__cli__.py,sha256=tRfbprNM4lcNzOdUF9bZBJUiPalFJgLPA5lSLBIJUYQ,252
18
+ tinybird/tb/__cli__.py,sha256=J8wIG9O6M4ZhVNRXbeTtwTp7z2fiJvI6E10Nn4-l4LI,252
19
19
  tinybird/tb/cli.py,sha256=H_HaZhkimKgkryYXpBjHfY9Qtg-ZORiONU3psDNpzDk,1135
20
20
  tinybird/tb/modules/auth.py,sha256=L1IatO2arRSzys3t8px8xVt8uPWUL5EVD0sFzAV_uVU,9022
21
21
  tinybird/tb/modules/build.py,sha256=h5drdmDFX8NHts9dA2Zepao7KSgMAl3DZGyFufVZP78,11085
22
22
  tinybird/tb/modules/cicd.py,sha256=cCq2NaW_YYlODoJLQGJE1cPNrHGgOqRP6Jkq554h3f8,5679
23
23
  tinybird/tb/modules/cli.py,sha256=XtdwMI5uPoKfhlpSuCuhzODRJfTCx1oXHz_bn3x1OBg,16047
24
- tinybird/tb/modules/common.py,sha256=e5g4hAELeb2QdIxrn9lJEtBQUV96peHKhNKptVEKBbg,83198
24
+ tinybird/tb/modules/common.py,sha256=6AmvMe8Uj-5A46aUlM3wJg7AilkJEAmHt1hTOb5IH2w,82957
25
25
  tinybird/tb/modules/config.py,sha256=FqdLpLaKpYubqw3xkB4EX06ufZYDgGRxONR_9i-y-KE,11416
26
26
  tinybird/tb/modules/connection.py,sha256=WKeDxbTpSsQ1PUmsT730g3S5RT2PtR5mPpVEanD1nbM,3933
27
27
  tinybird/tb/modules/copy.py,sha256=MAVqKip8_QhOYq99U_XuqSO6hCLJEh5sFtbhcXtI3SI,5802
28
28
  tinybird/tb/modules/create.py,sha256=FuJYuFqWy2kgSfxSwkQ5nExZgEYALyq_z9dc1d-FRN0,14078
29
29
  tinybird/tb/modules/datasource.py,sha256=dNCK9iCR2xPLfwqqwg2ixyE6NuoVEiJU2mBZBmOYrVY,16906
30
- tinybird/tb/modules/deployment.py,sha256=KMpIahNGUdea3KcH0jTMEnzQ-7zg7M4esd2zTfvaC-k,19337
30
+ tinybird/tb/modules/deployment.py,sha256=AuK63a7VXJ0K3YNGj2sFg6ZW1n5Ck-4i2zlZyMPariM,19466
31
31
  tinybird/tb/modules/endpoint.py,sha256=EhVoGAXsFz-83Fiwj1gI-I73iRRvL49d0W81un7hvPE,12080
32
32
  tinybird/tb/modules/exceptions.py,sha256=4A2sSjCEqKUMqpP3WI00zouCWW4uLaghXXLZBSw04mY,3363
33
33
  tinybird/tb/modules/feedback_manager.py,sha256=7nNiOx7OMebiheLED1r0d75SbuXCNxyBmF4e20rCBNc,69511
34
34
  tinybird/tb/modules/fmt.py,sha256=qpf9APqKTKL2uphNgdbj4OMVyLkAxZn6dn4eHF99L5g,3553
35
- tinybird/tb/modules/infra.py,sha256=4grSpfcm0gOHiMCYoIh26jx2mzeEEqgyMX8PetRMAWI,33246
35
+ tinybird/tb/modules/infra.py,sha256=GA5xnYLlVItPfJu_3_5NIdHQDuyfk2Z71wtcn9NncGA,33189
36
36
  tinybird/tb/modules/job.py,sha256=956Pj8BEEsiD2GZsV9RKKVM3I_CveOLgS82lykO5ukk,2963
37
37
  tinybird/tb/modules/llm.py,sha256=AC0VSphTOM2t-v1_3NLvNN_FIbgMo4dTyMqIv5nniPo,835
38
38
  tinybird/tb/modules/llm_utils.py,sha256=nS9r4FAElJw8yXtmdYrx-rtI2zXR8qXfi1QqUDCfxvg,3469
@@ -61,7 +61,7 @@ tinybird/tb/modules/datafile/build.py,sha256=jhfIJ2xt0N13XsLPe3iMQIyCPApHS13_Df2
61
61
  tinybird/tb/modules/datafile/build_common.py,sha256=rT7VJ5mnQ68R_8US91DAtkusfvjWuG_NObOzNgtN_ko,4562
62
62
  tinybird/tb/modules/datafile/build_datasource.py,sha256=CCU3eQ8Rax9RgHHfbAXDRL6rQ49N35h_GDQnGrUUUzA,17379
63
63
  tinybird/tb/modules/datafile/build_pipe.py,sha256=w-Wd08gZYAEcak9FdBijVfIU2_Wn_PPdgAZddPpoGTo,11382
64
- tinybird/tb/modules/datafile/common.py,sha256=HUuhEQ7lC5pqOxUw0NT76qwKlKjSlVAvaIIaXdgqMss,82327
64
+ tinybird/tb/modules/datafile/common.py,sha256=4Jv20MUMaQl2NlbviRGHH41ncoDc6h9g4IWC0nl0j3M,82579
65
65
  tinybird/tb/modules/datafile/diff.py,sha256=-0J7PsBO64T7LOZSkZ4ZFHHCPvT7cKItnJkbz2PkndU,6754
66
66
  tinybird/tb/modules/datafile/exceptions.py,sha256=8rw2umdZjtby85QbuRKFO5ETz_eRHwUY5l7eHsy1wnI,556
67
67
  tinybird/tb/modules/datafile/fixture.py,sha256=si-9LB-LdKQSWDtVW82xDrHtFfko5bgBG1cvjqqrcPU,1064
@@ -81,8 +81,8 @@ tinybird/tb_cli_modules/config.py,sha256=IsgdtFRnUrkY8-Zo32lmk6O7u3bHie1QCxLwgp4
81
81
  tinybird/tb_cli_modules/exceptions.py,sha256=pmucP4kTF4irIt7dXiG-FcnI-o3mvDusPmch1L8RCWk,3367
82
82
  tinybird/tb_cli_modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
83
83
  tinybird/tb_cli_modules/telemetry.py,sha256=Hh2Io8ZPROSunbOLuMvuIFU4TqwWPmQTqal4WS09K1A,10449
84
- tinybird-0.0.1.dev103.dist-info/METADATA,sha256=JB1oi-8Up8AsrEXhKLGoR0zXe7_8nTG9tG0UAQ45Wf4,1612
85
- tinybird-0.0.1.dev103.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
86
- tinybird-0.0.1.dev103.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
87
- tinybird-0.0.1.dev103.dist-info/top_level.txt,sha256=VqqqEmkAy7UNaD8-V51FCoMMWXjLUlR0IstvK7tJYVY,54
88
- tinybird-0.0.1.dev103.dist-info/RECORD,,
84
+ tinybird-0.0.1.dev105.dist-info/METADATA,sha256=mxeUNXYWE-C-m8ciGUCqE98J8sDAt-fD_PrOykb2Gq4,1612
85
+ tinybird-0.0.1.dev105.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
86
+ tinybird-0.0.1.dev105.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
87
+ tinybird-0.0.1.dev105.dist-info/top_level.txt,sha256=VqqqEmkAy7UNaD8-V51FCoMMWXjLUlR0IstvK7tJYVY,54
88
+ tinybird-0.0.1.dev105.dist-info/RECORD,,