tinybird 0.0.1.dev306__py3-none-any.whl → 1.0.5__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.
Files changed (45) hide show
  1. tinybird/datafile/common.py +4 -1
  2. tinybird/feedback_manager.py +3 -0
  3. tinybird/service_datasources.py +57 -8
  4. tinybird/sql_template.py +1 -1
  5. tinybird/sql_template_fmt.py +14 -4
  6. tinybird/tb/__cli__.py +2 -2
  7. tinybird/tb/cli.py +1 -0
  8. tinybird/tb/client.py +104 -22
  9. tinybird/tb/modules/agent/tools/execute_query.py +1 -1
  10. tinybird/tb/modules/agent/tools/request_endpoint.py +1 -1
  11. tinybird/tb/modules/branch.py +150 -0
  12. tinybird/tb/modules/build.py +51 -10
  13. tinybird/tb/modules/build_common.py +4 -2
  14. tinybird/tb/modules/cli.py +32 -10
  15. tinybird/tb/modules/common.py +161 -134
  16. tinybird/tb/modules/connection.py +125 -194
  17. tinybird/tb/modules/connection_kafka.py +382 -0
  18. tinybird/tb/modules/copy.py +3 -1
  19. tinybird/tb/modules/create.py +11 -0
  20. tinybird/tb/modules/datafile/build.py +1 -1
  21. tinybird/tb/modules/datafile/format_pipe.py +44 -5
  22. tinybird/tb/modules/datafile/playground.py +1 -1
  23. tinybird/tb/modules/datasource.py +475 -324
  24. tinybird/tb/modules/deployment.py +2 -0
  25. tinybird/tb/modules/deployment_common.py +81 -43
  26. tinybird/tb/modules/deprecations.py +4 -4
  27. tinybird/tb/modules/dev_server.py +33 -12
  28. tinybird/tb/modules/info.py +50 -7
  29. tinybird/tb/modules/job_common.py +15 -0
  30. tinybird/tb/modules/local.py +91 -21
  31. tinybird/tb/modules/local_common.py +320 -13
  32. tinybird/tb/modules/local_logs.py +209 -0
  33. tinybird/tb/modules/login.py +3 -2
  34. tinybird/tb/modules/login_common.py +252 -9
  35. tinybird/tb/modules/open.py +10 -5
  36. tinybird/tb/modules/project.py +14 -5
  37. tinybird/tb/modules/shell.py +14 -6
  38. tinybird/tb/modules/sink.py +3 -1
  39. tinybird/tb/modules/telemetry.py +7 -3
  40. tinybird/tb_cli_modules/telemetry.py +1 -1
  41. {tinybird-0.0.1.dev306.dist-info → tinybird-1.0.5.dist-info}/METADATA +29 -4
  42. {tinybird-0.0.1.dev306.dist-info → tinybird-1.0.5.dist-info}/RECORD +45 -41
  43. {tinybird-0.0.1.dev306.dist-info → tinybird-1.0.5.dist-info}/WHEEL +1 -1
  44. {tinybird-0.0.1.dev306.dist-info → tinybird-1.0.5.dist-info}/entry_points.txt +0 -0
  45. {tinybird-0.0.1.dev306.dist-info → tinybird-1.0.5.dist-info}/top_level.txt +0 -0
@@ -4,13 +4,13 @@
4
4
  # - But please, **do not** interleave utility functions and command definitions.
5
5
 
6
6
  import uuid
7
- from typing import Any, Dict, List, Optional, Tuple
7
+ from typing import Any, Dict, List, Optional
8
8
 
9
9
  import click
10
10
  from click import Context
11
- from confluent_kafka.admin import AdminClient
12
11
 
13
12
  from tinybird.tb.client import TinyB
13
+ from tinybird.tb.modules.build_common import process as build_project
14
14
  from tinybird.tb.modules.cli import cli
15
15
  from tinybird.tb.modules.common import (
16
16
  DataConnectorType,
@@ -18,21 +18,21 @@ from tinybird.tb.modules.common import (
18
18
  echo_safe_humanfriendly_tables_format_smart_table,
19
19
  get_gcs_connection_name,
20
20
  get_gcs_svc_account_creds,
21
- get_kafka_connection_name,
22
21
  get_s3_connection_name,
23
22
  production_aws_iamrole_only,
24
23
  run_aws_iamrole_connection_flow,
25
24
  run_gcp_svc_account_connection_flow,
26
- validate_kafka_auto_offset_reset,
27
- validate_kafka_bootstrap_servers,
28
- validate_kafka_key,
29
- validate_kafka_schema_registry_url,
30
- validate_kafka_secret,
25
+ )
26
+ from tinybird.tb.modules.connection_kafka import (
27
+ connection_create_kafka,
28
+ echo_kafka_data,
29
+ select_connection,
30
+ select_group_id,
31
+ select_topic,
31
32
  )
32
33
  from tinybird.tb.modules.create import (
33
34
  generate_aws_iamrole_connection_file_with_secret,
34
35
  generate_gcs_connection_file_with_secrets,
35
- generate_kafka_connection_with_secrets,
36
36
  )
37
37
  from tinybird.tb.modules.exceptions import CLIConnectionException
38
38
  from tinybird.tb.modules.feedback_manager import FeedbackManager
@@ -121,7 +121,8 @@ def connection_ls(ctx: Context, service: Optional[DataConnectorType] = None) ->
121
121
  obj: Dict[str, Any] = ctx.ensure_object(dict)
122
122
  client: TinyB = obj["client"]
123
123
 
124
- connections = client.connections(connector=service)
124
+ datasources = client.datasources()
125
+ connections = client.connections(connector=service, datasources=datasources)
125
126
  columns = []
126
127
  table = []
127
128
 
@@ -314,198 +315,128 @@ def connection_create_gcs(ctx: Context) -> None:
314
315
  )
315
316
 
316
317
 
317
- @connection_create.command(name="kafka", short_help="Creates a Kafka connection.")
318
+ @connection_create.command(name="kafka", help="Create a Kafka connection.")
319
+ @click.option("--connection-name", default=None, help="The name of the connection to identify it in Tinybird")
320
+ @click.option("--bootstrap-servers", default=None, help="Kafka Bootstrap Server in form mykafka.mycloud.com:9092")
321
+ @click.option("--key", default=None, help="Key/User")
322
+ @click.option("--secret", default=None, help="Secret/Password")
323
+ @click.option(
324
+ "--auto-offset-reset", default=None, help="Offset reset, can be 'latest' or 'earliest'. Defaults to 'latest'."
325
+ )
326
+ @click.option("--schema-registry-url", default=None, help="Avro Confluent Schema Registry URL")
327
+ @click.option(
328
+ "--sasl-mechanism",
329
+ default="PLAIN",
330
+ help="Authentication method for connection-based protocols. Defaults to 'PLAIN'",
331
+ )
332
+ @click.option(
333
+ "--security-protocol",
334
+ default="SASL_SSL",
335
+ help="Security protocol for connection-based protocols. Defaults to 'SASL_SSL'",
336
+ )
337
+ @click.option("--ssl-ca-pem", default=None, help="Path or content of the CA Certificate file in PEM format")
318
338
  @click.pass_context
319
- def connection_create_kafka_cmd(ctx: Context) -> None:
320
- """
321
- Creates a Kafka connection.
322
-
323
- \b
324
- $ tb connection create kafka
325
- """
326
- connection_create_kafka(ctx)
327
-
328
-
329
- def connection_create_kafka(ctx: Context) -> Tuple[str, str, str, str, str, str, str, str, List[str]]:
330
- obj: Dict[str, Any] = ctx.ensure_object(dict)
331
- click.echo(FeedbackManager.gray(message="\n» Creating Kafka connection..."))
339
+ def connection_create_kafka_cmd(
340
+ ctx: Context,
341
+ connection_name: Optional[str],
342
+ bootstrap_servers: Optional[str],
343
+ key: Optional[str],
344
+ secret: Optional[str],
345
+ auto_offset_reset: Optional[str],
346
+ schema_registry_url: Optional[str],
347
+ sasl_mechanism: Optional[str],
348
+ security_protocol: Optional[str],
349
+ ssl_ca_pem: Optional[str],
350
+ ) -> None:
351
+ env: str = ctx.ensure_object(dict)["env"]
332
352
  project: Project = ctx.ensure_object(dict)["project"]
333
- name = get_kafka_connection_name(project.folder, "")
334
- default_bootstrap_servers = "localhost:9092"
335
- bootstrap_servers = click.prompt(
336
- FeedbackManager.highlight(
337
- message=f"? Bootstrap servers (comma-separated list of host:port pairs) [{default_bootstrap_servers}]"
338
- ),
339
- default=default_bootstrap_servers,
340
- show_default=False,
341
- )
342
- if not bootstrap_servers:
343
- bootstrap_servers = click.prompt("Bootstrap Server")
344
-
345
- validate_kafka_bootstrap_servers(bootstrap_servers)
346
- secret_required = click.confirm(
347
- FeedbackManager.highlight(message=" ? Do you want to store the bootstrap server in a .env.local file? [Y/n]"),
348
- default=True,
349
- show_default=False,
350
- )
351
- tb_secret_bootstrap_servers: Optional[str] = None
352
- tb_secret_key: Optional[str] = None
353
- tb_secret_secret: Optional[str] = None
354
-
355
- if secret_required:
356
- tb_secret_bootstrap_servers = str(click.prompt(FeedbackManager.highlight(message=" ? Secret name")))
357
- try:
358
- save_secret_to_env_file(project=project, name=tb_secret_bootstrap_servers, value=bootstrap_servers)
359
- except Exception as e:
360
- raise CLIConnectionException(FeedbackManager.error(message=str(e)))
361
-
362
- key = click.prompt(FeedbackManager.highlight(message="? Kafka key"))
363
-
364
- validate_kafka_key(key)
365
-
366
- secret_required = click.confirm(
367
- FeedbackManager.highlight(message=" ? Do you want to store the Kafka key in a .env.local file? [Y/n]"),
368
- default=True,
369
- show_default=False,
370
- )
371
-
372
- if secret_required:
373
- tb_secret_key = str(click.prompt(FeedbackManager.highlight(message=" ? Secret name")))
374
- try:
375
- save_secret_to_env_file(project=project, name=tb_secret_key, value=key)
376
- except Exception as e:
377
- raise CLIConnectionException(FeedbackManager.error(message=str(e)))
378
-
379
- secret = click.prompt(FeedbackManager.highlight(message="? Kafka secret"), hide_input=True)
380
-
381
- validate_kafka_secret(secret)
382
-
383
- secret_required = click.confirm(
384
- FeedbackManager.highlight(message=" ? Do you want to store the Kafka secret in a .env.local file? [Y/n]"),
385
- default=True,
386
- show_default=False,
387
- )
388
-
389
- if secret_required:
390
- tb_secret_secret = str(click.prompt(FeedbackManager.highlight(message=" ? Secret name")))
391
- try:
392
- save_secret_to_env_file(project=project, name=tb_secret_secret, value=secret)
393
- except Exception as e:
394
- raise CLIConnectionException(FeedbackManager.error(message=str(e)))
395
-
396
- security_protocol_options = ["SASL_SSL", "PLAINTEXT"]
397
- security_protocol = click.prompt(
398
- FeedbackManager.highlight(message="? Security Protocol (SASL_SSL, PLAINTEXT) [SASL_SSL]"),
399
- type=click.Choice(security_protocol_options),
400
- show_default=False,
401
- show_choices=False,
402
- default="SASL_SSL",
403
- )
404
-
405
- sasl_mechanism_options = ["PLAIN", "SCRAM-SHA-256", "SCRAM-SHA-512"]
406
- sasl_mechanism = click.prompt(
407
- FeedbackManager.highlight(message="? SASL Mechanism (PLAIN, SCRAM-SHA-256, SCRAM-SHA-512) [PLAIN]"),
408
- type=click.Choice(sasl_mechanism_options),
409
- show_default=False,
410
- show_choices=False,
411
- default="PLAIN",
412
- )
413
-
414
- create_in_cloud = (
415
- click.confirm(
416
- FeedbackManager.highlight(
417
- message="? Would you like to create this connection in the cloud environment as well? [Y/n]"
418
- ),
419
- default=True,
353
+ client: TinyB = ctx.ensure_object(dict)["client"]
354
+ config: Dict[str, Any] = ctx.ensure_object(dict)["config"]
355
+ if env == "local":
356
+ should_build = click.confirm(
357
+ FeedbackManager.highlight(message="? Do you want to build the project before continue? [Y/n]"),
420
358
  show_default=False,
359
+ default=True,
421
360
  )
422
- if obj["env"] == "local" and (tb_secret_bootstrap_servers or tb_secret_key or tb_secret_secret)
423
- else False
424
- )
425
-
426
- if create_in_cloud:
427
- click.echo(FeedbackManager.gray(message="» Creating Secrets in cloud environment..."))
428
- prod_config = obj["config"]
429
- host = prod_config["host"]
430
- token = prod_config["token"]
431
- prod_client = TinyB(
432
- token=token,
433
- host=host,
434
- staging=False,
435
- )
436
- if tb_secret_bootstrap_servers:
437
- prod_client.create_secret(name=tb_secret_bootstrap_servers, value=bootstrap_servers)
438
- if tb_secret_key:
439
- prod_client.create_secret(name=tb_secret_key, value=key)
440
- if tb_secret_secret:
441
- prod_client.create_secret(name=tb_secret_secret, value=secret)
442
- click.echo(FeedbackManager.success(message="✓ Secrets created!"))
443
-
444
- schema_registry_url = click.prompt(
445
- FeedbackManager.highlight(message="? Schema Registry URL (optional)"),
446
- default="",
447
- show_default=False,
448
- )
449
- if schema_registry_url:
450
- validate_kafka_schema_registry_url(schema_registry_url)
451
-
452
- auto_offset_reset_options = ["latest", "earliest"]
453
- auto_offset_reset = click.prompt(
454
- FeedbackManager.highlight(message="? Auto offset reset (latest, earliest) [latest]"),
455
- type=click.Choice(auto_offset_reset_options),
456
- default="latest",
457
- show_default=False,
458
- show_choices=False,
459
- )
460
- validate_kafka_auto_offset_reset(auto_offset_reset)
461
- click.echo(FeedbackManager.gray(message="» Validating connection..."))
462
-
463
- topics = list_kafka_topics(bootstrap_servers, key, secret, security_protocol, sasl_mechanism)
464
-
465
- if topics is None:
466
- raise CLIConnectionException(FeedbackManager.error(message="Invalid Kafka connection"))
467
-
468
- click.echo(FeedbackManager.success(message="✓ Connection is valid"))
469
- generate_kafka_connection_with_secrets(
470
- name=name,
361
+ if should_build:
362
+ click.echo(FeedbackManager.gray(message="» Building project..."))
363
+ build_project(project=project, tb_client=client, watch=False, config=config, silent=True)
364
+ click.echo(FeedbackManager.success(message="✓ Build completed"))
365
+ else:
366
+ click.echo(FeedbackManager.gray(message="Skipping build..."))
367
+
368
+ result = connection_create_kafka(
369
+ ctx,
370
+ connection_name=connection_name,
471
371
  bootstrap_servers=bootstrap_servers,
472
- tb_secret_bootstrap_servers=tb_secret_bootstrap_servers,
473
372
  key=key,
474
- tb_secret_key=tb_secret_key,
475
373
  secret=secret,
476
- tb_secret_secret=tb_secret_secret,
477
- security_protocol=security_protocol,
374
+ auto_offset_reset=auto_offset_reset,
375
+ schema_registry_url=schema_registry_url,
478
376
  sasl_mechanism=sasl_mechanism,
479
- folder=project.folder,
480
- )
481
- click.echo(FeedbackManager.info_file_created(file=f"connections/{name}.connection"))
482
- click.echo(FeedbackManager.success(message="✓ Connection created!"))
483
- return (
484
- name,
485
- bootstrap_servers,
486
- key,
487
- secret,
488
- schema_registry_url,
489
- auto_offset_reset,
490
- sasl_mechanism,
491
- security_protocol,
492
- topics,
377
+ security_protocol=security_protocol,
378
+ ssl_ca_pem=ssl_ca_pem,
493
379
  )
494
380
 
381
+ if not result["error"]:
382
+ yes = click.confirm(
383
+ FeedbackManager.highlight(message="? Would you like to preview data from the connection?"),
384
+ default=True,
385
+ show_default=False,
386
+ )
387
+ if yes:
388
+ connection_data(connection_name=result["name"], client=client)
389
+ else:
390
+ click.echo(FeedbackManager.gray(message="Skipping data preview."))
391
+
392
+
393
+ @connection.command(name="data", help="Preview data from an existing connection.")
394
+ @click.argument("connection_name", type=str, required=False)
395
+ @click.option("--kafka-topic", type=str, help="The Kafka topic to preview")
396
+ @click.option("--kafka-group-id", type=str, help="The Kafka group ID to use for preview")
397
+ @click.pass_context
398
+ def connection_data_cmd(
399
+ ctx: Context,
400
+ connection_name: Optional[str] = None,
401
+ kafka_topic: Optional[str] = None,
402
+ kafka_group_id: Optional[str] = None,
403
+ ) -> None:
404
+ project: Project = ctx.ensure_object(dict)["project"]
405
+ client: TinyB = ctx.ensure_object(dict)["client"]
406
+ env: str = ctx.ensure_object(dict)["env"]
407
+ config: Dict[str, Any] = ctx.ensure_object(dict)["config"]
408
+
409
+ if env == "local":
410
+ click.echo(FeedbackManager.gray(message="» Building project to access the latest connections..."))
411
+ build_project(project=project, tb_client=client, watch=False, config=config, silent=True)
412
+ click.echo(FeedbackManager.success(message="✓ Build completed"))
413
+
414
+ if connection_name is None:
415
+ connections = client.connections("kafka")
416
+ connection = select_connection(None, "kafka", connections, client)
417
+ connection_name = connection["name"]
418
+
419
+ connection_data(connection_name, client, kafka_topic, kafka_group_id)
420
+
421
+
422
+ def connection_data(
423
+ connection_name: str,
424
+ client: TinyB,
425
+ kafka_topic: Optional[str] = None,
426
+ kafka_group_id: Optional[str] = None,
427
+ ) -> None:
428
+ connection = next((c for c in client.connections() if c["name"] == connection_name), None)
429
+ if not connection:
430
+ raise CLIConnectionException(FeedbackManager.error(message=f"Connection {connection_name} not found."))
431
+
432
+ if connection["service"] != DataConnectorType.KAFKA:
433
+ raise CLIConnectionException(
434
+ FeedbackManager.error(
435
+ message=f"{connection['service']} connections are not supported yet for previewing data. Supported connections: kafka"
436
+ )
437
+ )
495
438
 
496
- def list_kafka_topics(bootstrap_servers, sasl_username, sasl_password, security_protocol, sasl_mechanism):
497
- conf = {
498
- "bootstrap.servers": bootstrap_servers,
499
- "security.protocol": security_protocol,
500
- "sasl.mechanism": sasl_mechanism,
501
- "sasl.username": sasl_username,
502
- "sasl.password": sasl_password,
503
- "log_level": 0,
504
- }
505
-
506
- try:
507
- client = AdminClient(conf)
508
- metadata = client.list_topics(timeout=5)
509
- return list(metadata.topics.keys())
510
- except Exception:
511
- return None
439
+ connection_id = connection["id"]
440
+ topic = select_topic(kafka_topic, connection_id, client)
441
+ group_id = select_group_id(kafka_group_id, topic, connection_id, client)
442
+ echo_kafka_data(connection_id, connection_name, topic, group_id, client)