tinybird 0.0.1.dev292__tar.gz → 0.0.1.dev294__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.

Potentially problematic release.


This version of tinybird might be problematic. Click here for more details.

Files changed (150) hide show
  1. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/PKG-INFO +1 -1
  2. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/ch_utils/constants.py +1 -0
  3. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/datafile/parse_pipe.py +2 -2
  4. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/sql_template.py +11 -3
  5. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/__cli__.py +2 -2
  6. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/agent.py +14 -9
  7. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/build.py +5 -3
  8. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/build_common.py +140 -1
  9. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/datasource.py +1 -1
  10. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/feedback_manager.py +1 -1
  11. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/local_common.py +14 -2
  12. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/test.py +7 -4
  13. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/test_common.py +19 -10
  14. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird.egg-info/PKG-INFO +1 -1
  15. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/setup.cfg +0 -0
  16. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/__cli__.py +0 -0
  17. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/ch_utils/engine.py +0 -0
  18. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/check_pypi.py +0 -0
  19. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/client.py +0 -0
  20. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/config.py +0 -0
  21. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/connectors.py +0 -0
  22. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/context.py +0 -0
  23. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/datafile/common.py +0 -0
  24. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/datafile/exceptions.py +0 -0
  25. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/datafile/parse_connection.py +0 -0
  26. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/datafile/parse_datasource.py +0 -0
  27. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/datatypes.py +0 -0
  28. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/feedback_manager.py +0 -0
  29. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/git_settings.py +0 -0
  30. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/prompts.py +0 -0
  31. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/service_datasources.py +0 -0
  32. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/sql.py +0 -0
  33. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/sql_template_fmt.py +0 -0
  34. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/sql_toolset.py +0 -0
  35. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/syncasync.py +0 -0
  36. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/check_pypi.py +0 -0
  37. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/cli.py +0 -0
  38. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/client.py +0 -0
  39. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/config.py +0 -0
  40. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/__init__.py +0 -0
  41. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/animations.py +0 -0
  42. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/banner.py +0 -0
  43. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/command_agent.py +0 -0
  44. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/compactor.py +0 -0
  45. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/explore_agent.py +0 -0
  46. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/file_agent.py +0 -0
  47. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/memory.py +0 -0
  48. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/mock_agent.py +0 -0
  49. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/models.py +0 -0
  50. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/prompts.py +0 -0
  51. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/testing_agent.py +0 -0
  52. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/__init__.py +0 -0
  53. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/analyze.py +0 -0
  54. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/append.py +0 -0
  55. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/build.py +0 -0
  56. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/datafile.py +0 -0
  57. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/deploy.py +0 -0
  58. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/deploy_check.py +0 -0
  59. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/diff_resource.py +0 -0
  60. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/execute_query.py +0 -0
  61. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/file.py +0 -0
  62. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/get_endpoint_stats.py +0 -0
  63. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/get_openapi_definition.py +0 -0
  64. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/mock.py +0 -0
  65. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/plan.py +0 -0
  66. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/request_endpoint.py +0 -0
  67. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/run_command.py +0 -0
  68. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/secret.py +0 -0
  69. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/tools/test.py +0 -0
  70. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/agent/utils.py +0 -0
  71. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/cicd.py +0 -0
  72. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/cli.py +0 -0
  73. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/common.py +0 -0
  74. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/config.py +0 -0
  75. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/connection.py +0 -0
  76. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/copy.py +0 -0
  77. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/create.py +0 -0
  78. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/datafile/build.py +0 -0
  79. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/datafile/build_common.py +0 -0
  80. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  81. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  82. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/datafile/diff.py +0 -0
  83. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/datafile/fixture.py +0 -0
  84. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/datafile/format_common.py +0 -0
  85. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  86. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  87. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  88. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/datafile/playground.py +0 -0
  89. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/datafile/pull.py +0 -0
  90. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/deployment.py +0 -0
  91. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/deployment_common.py +0 -0
  92. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/deprecations.py +0 -0
  93. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/dev_server.py +0 -0
  94. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/endpoint.py +0 -0
  95. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/exceptions.py +0 -0
  96. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/info.py +0 -0
  97. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/infra.py +0 -0
  98. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/job.py +0 -0
  99. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/llm.py +0 -0
  100. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/llm_utils.py +0 -0
  101. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/local.py +0 -0
  102. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/login.py +0 -0
  103. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/login_common.py +0 -0
  104. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/logout.py +0 -0
  105. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/materialization.py +0 -0
  106. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/mock.py +0 -0
  107. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/mock_common.py +0 -0
  108. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/open.py +0 -0
  109. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/pipe.py +0 -0
  110. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/project.py +0 -0
  111. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/regions.py +0 -0
  112. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/secret.py +0 -0
  113. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/secret_common.py +0 -0
  114. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/shell.py +0 -0
  115. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/sink.py +0 -0
  116. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/table.py +0 -0
  117. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/telemetry.py +0 -0
  118. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  119. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  120. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/token.py +0 -0
  121. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/watch.py +0 -0
  122. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/workspace.py +0 -0
  123. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb/modules/workspace_members.py +0 -0
  124. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli.py +0 -0
  125. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/auth.py +0 -0
  126. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/branch.py +0 -0
  127. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/cicd.py +0 -0
  128. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/cli.py +0 -0
  129. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/common.py +0 -0
  130. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/config.py +0 -0
  131. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/connection.py +0 -0
  132. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/datasource.py +0 -0
  133. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/exceptions.py +0 -0
  134. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/fmt.py +0 -0
  135. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/job.py +0 -0
  136. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/pipe.py +0 -0
  137. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/regions.py +0 -0
  138. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/tag.py +0 -0
  139. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/telemetry.py +0 -0
  140. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/test.py +0 -0
  141. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  142. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  143. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/workspace.py +0 -0
  144. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  145. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird/tornado_template.py +0 -0
  146. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird.egg-info/SOURCES.txt +0 -0
  147. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird.egg-info/dependency_links.txt +0 -0
  148. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird.egg-info/entry_points.txt +0 -0
  149. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird.egg-info/requires.txt +0 -0
  150. {tinybird-0.0.1.dev292 → tinybird-0.0.1.dev294}/tinybird.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev292
3
+ Version: 0.0.1.dev294
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -258,4 +258,5 @@ VALID_QUERY_FORMATS = (
258
258
  "RowBinaryWithNamesAndTypes",
259
259
  "TabSeparated",
260
260
  "JSONCompactEachRowWithNamesAndTypes",
261
+ "TabSeparatedWithNamesAndTypes",
261
262
  )
@@ -11,7 +11,7 @@ from tinybird.datafile.common import (
11
11
  parse,
12
12
  )
13
13
  from tinybird.datafile.exceptions import IncludeFileNotFoundException, ParseException
14
- from tinybird.sql_template import get_template_and_variables, render_sql_template, secret_template_key
14
+ from tinybird.sql_template import get_template_and_variables, render_sql_template
15
15
  from tinybird.tb.modules.feedback_manager import FeedbackManager
16
16
  from tinybird.tornado_template import UnClosedIfError
17
17
 
@@ -54,7 +54,7 @@ def parse_pipe(
54
54
  if sql.strip()[0] == "%":
55
55
  secrets_list: Optional[List[str]] = None
56
56
  if secrets:
57
- secrets_list = [f"{secret_template_key(secret)}" for secret in secrets.keys()]
57
+ secrets_list = list(secrets.keys())
58
58
  # Setting test_mode=True to ignore errors on required parameters and
59
59
  # secrets_in_test_mode=False to raise errors on missing secrets
60
60
  sql, _, variable_warnings = render_sql_template(
@@ -1405,8 +1405,11 @@ def generate(self, **kwargs) -> Tuple[str, TemplateExecutionResults]:
1405
1405
  namespace = {}
1406
1406
  template_execution_results = TemplateExecutionResults()
1407
1407
  for key in kwargs.get("tb_secrets", []):
1408
+ # Avoid double-prefixing if the key already has the tb_secret_ prefix
1408
1409
  if is_secret_template_key(key):
1409
1410
  template_execution_results.add_template_param(key)
1411
+ else:
1412
+ template_execution_results.add_template_param(secret_template_key(key))
1410
1413
 
1411
1414
  if TB_SECRET_IN_TEST_MODE in kwargs:
1412
1415
  template_execution_results[TB_SECRET_IN_TEST_MODE] = None
@@ -1415,15 +1418,20 @@ def generate(self, **kwargs) -> Tuple[str, TemplateExecutionResults]:
1415
1418
  try:
1416
1419
  key = secret_template_key(x)
1417
1420
  if key in template_execution_results.template_params:
1421
+ # secret available: Always use workspace secret regardless of test mode
1418
1422
  template_execution_results.add_ch_param(x)
1419
1423
  return Symbol("{" + sqlescape(x) + ": String}")
1420
1424
  else:
1425
+ # secret not available: Check test mode and defaults
1421
1426
  is_test_mode = TB_SECRET_IN_TEST_MODE in template_execution_results
1422
- if is_test_mode and default is None:
1423
- return Symbol("{" + sqlescape(x) + ": String}")
1424
- elif default is not None:
1427
+ if default is not None:
1428
+ # Use provided default value
1425
1429
  return default
1430
+ elif is_test_mode:
1431
+ # In test mode without default - return placeholder
1432
+ return Symbol("{" + sqlescape(x) + ": String}")
1426
1433
  else:
1434
+ # Not in test mode, no secret, no default - raise error
1427
1435
  raise SQLTemplateException(
1428
1436
  f"Cannot access secret '{x}'. Check the secret exists in the Workspace and the token has the required scope."
1429
1437
  )
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
4
4
  __url__ = 'https://www.tinybird.co/docs/forward/commands'
5
5
  __author__ = 'Tinybird'
6
6
  __author_email__ = 'support@tinybird.co'
7
- __version__ = '0.0.1.dev292'
8
- __revision__ = '78dba1d'
7
+ __version__ = '0.0.1.dev294'
8
+ __revision__ = 'b3b73ff'
@@ -373,7 +373,7 @@ class TinybirdAgent:
373
373
  execute_query_local=partial(execute_query_local, config=config),
374
374
  request_endpoint_cloud=partial(request_endpoint_cloud, config=config),
375
375
  request_endpoint_local=partial(request_endpoint_local, config=config),
376
- build_project_test=partial(build_project_test, project=project, client=test_client),
376
+ build_project_test=partial(build_project_test, project=project, client=test_client, config=config),
377
377
  get_pipe_data_test=partial(get_pipe_data_test, client=test_client),
378
378
  get_datasource_datafile_cloud=partial(get_datasource_datafile_cloud, config=config),
379
379
  get_datasource_datafile_local=partial(get_datasource_datafile_local, config=config),
@@ -382,7 +382,7 @@ class TinybirdAgent:
382
382
  get_connection_datafile_cloud=partial(get_connection_datafile_cloud, config=config),
383
383
  get_connection_datafile_local=partial(get_connection_datafile_local, config=config),
384
384
  get_project_files=project.get_project_files,
385
- run_tests=partial(run_tests, project=project, client=test_client),
385
+ run_tests=partial(run_tests, project=project, client=test_client, config=config),
386
386
  folder=folder,
387
387
  thinking_animation=self.thinking_animation,
388
388
  workspace_id=self.workspace_id,
@@ -482,9 +482,9 @@ def run_agent(
482
482
  if yes:
483
483
  update_cli()
484
484
  click.echo(FeedbackManager.highlight(message="» Initializing Tinybird Code..."))
485
- token = config.get("token", None)
486
- host = config.get("host", None)
487
- user_token = config.get("user_token", None)
485
+ token = config.get("token", "")
486
+ host = config.get("host", "")
487
+ user_token = config.get("user_token", "")
488
488
  workspace_id = config.get("id", "")
489
489
  workspace_name = config.get("name", "")
490
490
  try:
@@ -501,8 +501,8 @@ def run_agent(
501
501
  login(host, auth_host="https://cloud.tinybird.co", workspace=None, interactive=False, method="browser")
502
502
  cli_config = CLIConfig.get_project_config()
503
503
  config = {**config, **cli_config.to_dict()}
504
- token = cli_config.get_token()
505
- user_token = cli_config.get_user_token()
504
+ token = cli_config.get_token() or ""
505
+ user_token = cli_config.get_user_token() or ""
506
506
  host = cli_config.get_host()
507
507
  workspace_id = cli_config.get("id", "")
508
508
  workspace_name = cli_config.get("name", "")
@@ -652,6 +652,7 @@ def build_project(
652
652
  build_error = build_process(
653
653
  project=project,
654
654
  tb_client=client,
655
+ config=config,
655
656
  watch=False,
656
657
  silent=silent,
657
658
  exit_on_error=False,
@@ -664,11 +665,13 @@ def build_project(
664
665
  def build_project_test(
665
666
  client: TinyB,
666
667
  project: Project,
668
+ config: dict[str, Any],
667
669
  silent: bool = False,
668
670
  ) -> None:
669
671
  build_error = build_process(
670
672
  project=project,
671
673
  tb_client=client,
674
+ config=config,
672
675
  watch=False,
673
676
  silent=silent,
674
677
  exit_on_error=False,
@@ -821,9 +824,11 @@ def get_connection_datafile_local(config: dict[str, Any], connection_name: str)
821
824
  return "Connection not found"
822
825
 
823
826
 
824
- def run_tests(client: TinyB, project: Project, pipe_name: Optional[str] = None) -> Optional[str]:
827
+ def run_tests(
828
+ client: TinyB, project: Project, config: dict[str, Any], pipe_name: Optional[str] = None
829
+ ) -> Optional[str]:
825
830
  try:
826
- return run_tests_common(name=(pipe_name,) if pipe_name else (), project=project, client=client)
831
+ return run_tests_common(name=(pipe_name,) if pipe_name else (), project=project, client=client, config=config)
827
832
  except SystemExit as e:
828
833
  raise Exception(e.args[0])
829
834
 
@@ -34,6 +34,7 @@ def build(ctx: click.Context, watch: bool) -> None:
34
34
  obj: Dict[str, Any] = ctx.ensure_object(dict)
35
35
  project: Project = ctx.ensure_object(dict)["project"]
36
36
  tb_client: TinyB = ctx.ensure_object(dict)["client"]
37
+ config: Dict[str, Any] = ctx.ensure_object(dict)["config"]
37
38
  if obj["env"] == "cloud":
38
39
  raise click.ClickException(FeedbackManager.error_build_only_supported_in_local())
39
40
 
@@ -47,12 +48,12 @@ def build(ctx: click.Context, watch: bool) -> None:
47
48
  )
48
49
 
49
50
  click.echo(FeedbackManager.highlight_building_project())
50
- process(project=project, tb_client=tb_client, watch=False)
51
+ process(project=project, tb_client=tb_client, watch=False, config=config)
51
52
  if watch:
52
53
  run_watch(
53
54
  project=project,
54
55
  tb_client=tb_client,
55
- process=partial(process, project=project, tb_client=tb_client, watch=True),
56
+ process=partial(process, project=project, tb_client=tb_client, watch=True, config=config),
56
57
  )
57
58
 
58
59
 
@@ -65,6 +66,7 @@ def dev(ctx: click.Context, data_origin: str, ui: bool) -> None:
65
66
  return dev_cloud(ctx)
66
67
  project: Project = ctx.ensure_object(dict)["project"]
67
68
  tb_client: TinyB = ctx.ensure_object(dict)["client"]
69
+ config: Dict[str, Any] = ctx.ensure_object(dict)["config"]
68
70
  build_status = BuildStatus()
69
71
  if ui:
70
72
  server_thread = threading.Thread(
@@ -75,7 +77,7 @@ def dev(ctx: click.Context, data_origin: str, ui: bool) -> None:
75
77
  time.sleep(0.5)
76
78
 
77
79
  click.echo(FeedbackManager.highlight_building_project())
78
- process(project=project, tb_client=tb_client, watch=True, build_status=build_status)
80
+ process(project=project, tb_client=tb_client, watch=True, config=config, build_status=build_status)
79
81
  run_watch(
80
82
  project=project,
81
83
  tb_client=tb_client,
@@ -1,18 +1,21 @@
1
1
  import json
2
2
  import logging
3
3
  import time
4
+ from copy import deepcopy
4
5
  from pathlib import Path
5
- from typing import Optional
6
+ from typing import Any, Optional
6
7
  from urllib.parse import urlencode, urljoin
7
8
 
8
9
  import click
9
10
  import requests
10
11
 
12
+ from tinybird.datafile.parse_datasource import parse_datasource
11
13
  from tinybird.tb.client import TinyB
12
14
  from tinybird.tb.modules.common import push_data, sys_exit
13
15
  from tinybird.tb.modules.datafile.fixture import FixtureExtension, get_fixture_dir, persist_fixture
14
16
  from tinybird.tb.modules.dev_server import BuildStatus
15
17
  from tinybird.tb.modules.feedback_manager import FeedbackManager
18
+ from tinybird.tb.modules.local_common import get_local_tokens
16
19
  from tinybird.tb.modules.project import Project
17
20
  from tinybird.tb.modules.shell import print_table_formatted
18
21
 
@@ -21,6 +24,7 @@ def process(
21
24
  project: Project,
22
25
  tb_client: TinyB,
23
26
  watch: bool,
27
+ config: dict[str, Any],
24
28
  file_changed: Optional[str] = None,
25
29
  diff: Optional[str] = None,
26
30
  silent: bool = False,
@@ -29,6 +33,12 @@ def process(
29
33
  load_fixtures: bool = True,
30
34
  ) -> Optional[str]:
31
35
  time_start = time.time()
36
+
37
+ # Build vendored workspaces before build
38
+ build_vendored_workspaces(project=project, tb_client=tb_client, config=config)
39
+ # Ensure SHARED_WITH workspaces exist before build
40
+ build_shared_with_workspaces(project=project, tb_client=tb_client, config=config)
41
+
32
42
  build_failed = False
33
43
  build_error: Optional[str] = None
34
44
  build_result: Optional[bool] = None
@@ -320,3 +330,132 @@ def echo_changes(project: Project, changes: list[str], extension: str, status: s
320
330
  if path_str:
321
331
  path_str = path_str.replace(f"{project.folder}/", "")
322
332
  click.echo(FeedbackManager.info(message=f"✓ {path_str} {status}"))
333
+
334
+
335
+ def find_workspace_or_create(user_client: TinyB, workspace_name: str) -> Optional[str]:
336
+ # Get a client scoped to the vendored workspace using the user token
337
+ ws_token = None
338
+ org_id = None
339
+ try:
340
+ # Fetch org id and workspaces with tokens
341
+ info = user_client.user_workspaces_with_organization(version="v1")
342
+ org_id = info.get("organization_id")
343
+ workspaces = info.get("workspaces", [])
344
+ found = next((w for w in workspaces if w.get("name") == workspace_name), None)
345
+ if found:
346
+ ws_token = found.get("token")
347
+ # If still not found, try the generic listing
348
+ if not ws_token:
349
+ workspaces_full = user_client.user_workspaces_and_branches(version="v1")
350
+ created_ws = next(
351
+ (w for w in workspaces_full.get("workspaces", []) if w.get("name") == workspace_name), None
352
+ )
353
+ if created_ws:
354
+ ws_token = created_ws.get("token")
355
+ except Exception:
356
+ ws_token = None
357
+
358
+ # If workspace doesn't exist, try to create it and fetch its token
359
+ if not ws_token:
360
+ try:
361
+ user_client.create_workspace(workspace_name, assign_to_organization_id=org_id, version="v1")
362
+ # Fetch token for newly created workspace
363
+ info_after = user_client.user_workspaces_and_branches(version="v1")
364
+ created = next((w for w in info_after.get("workspaces", []) if w.get("name") == workspace_name), None)
365
+ ws_token = created.get("token") if created else None
366
+ except Exception as e:
367
+ click.echo(
368
+ FeedbackManager.warning(
369
+ message=(f"Skipping vendored workspace '{workspace_name}': unable to create or resolve token ({e})")
370
+ )
371
+ )
372
+
373
+ return ws_token
374
+
375
+
376
+ def build_vendored_workspaces(project: Project, tb_client: TinyB, config: dict[str, Any]) -> None:
377
+ """Build each vendored workspace under project.vendor_path if present.
378
+
379
+ Directory structure expected: vendor/<workspace_name>/<data_project_inside>
380
+ Each top-level directory under vendor is treated as a separate workspace
381
+ whose project files will be built using that workspace's token.
382
+ """
383
+ try:
384
+ vendor_root = Path(project.vendor_path)
385
+
386
+ if not vendor_root.exists() or not vendor_root.is_dir():
387
+ return
388
+
389
+ tokens = get_local_tokens()
390
+ user_token = tokens["user_token"]
391
+ user_client = deepcopy(tb_client)
392
+ user_client.token = user_token
393
+
394
+ # Iterate over vendored workspace folders
395
+ for ws_dir in sorted([p for p in vendor_root.iterdir() if p.is_dir()]):
396
+ workspace_name = ws_dir.name
397
+ ws_token = find_workspace_or_create(user_client, workspace_name)
398
+
399
+ if not ws_token:
400
+ click.echo(
401
+ FeedbackManager.warning(
402
+ message=f"Skipping vendored workspace '{workspace_name}': could not resolve token after creation"
403
+ )
404
+ )
405
+ continue
406
+
407
+ # Build using a client scoped to the vendor workspace token
408
+ vendor_client = deepcopy(tb_client)
409
+ vendor_client.token = ws_token
410
+ vendor_project = Project(folder=str(ws_dir), workspace_name=workspace_name, max_depth=project.max_depth)
411
+
412
+ # Do not exit on error to allow main project to continue
413
+ process(
414
+ project=vendor_project,
415
+ tb_client=vendor_client,
416
+ watch=False,
417
+ silent=True,
418
+ exit_on_error=True,
419
+ load_fixtures=True,
420
+ config=config,
421
+ )
422
+ except Exception as e:
423
+ # Never break the main build due to vendored build errors
424
+ click.echo(FeedbackManager.error_exception(error=e))
425
+
426
+
427
+ def build_shared_with_workspaces(project: Project, tb_client: TinyB, config: dict[str, Any]) -> None:
428
+ """Scan project for .datasource files and ensure SHARED_WITH workspaces exist."""
429
+
430
+ try:
431
+ # Gather SHARED_WITH workspace names from all .datasource files
432
+ datasource_files = project.get_datasource_files()
433
+ shared_ws_names = set()
434
+
435
+ for filename in datasource_files:
436
+ try:
437
+ doc = parse_datasource(filename).datafile
438
+ for ws_name in doc.shared_with or []:
439
+ shared_ws_names.add(ws_name)
440
+ except Exception:
441
+ # Ignore parse errors here; they'll be handled during the main process()
442
+ continue
443
+
444
+ if not shared_ws_names:
445
+ return
446
+
447
+ # Need a user token to list/create workspaces
448
+ tokens = get_local_tokens()
449
+ user_token = tokens.get("user_token")
450
+ if not user_token:
451
+ click.echo(FeedbackManager.info_skipping_shared_with_entry())
452
+ return
453
+
454
+ user_client = deepcopy(tb_client)
455
+ user_client.token = user_token
456
+
457
+ # Ensure each SHARED_WITH workspace exists
458
+ for ws_name in sorted(shared_ws_names):
459
+ find_workspace_or_create(user_client, ws_name)
460
+ except Exception as e:
461
+ click.echo(FeedbackManager.error_exception(error=e))
@@ -931,7 +931,7 @@ def datasource_create(
931
931
  default=True,
932
932
  ):
933
933
  click.echo(FeedbackManager.gray(message="» Building project..."))
934
- build_project(project=project, tb_client=client, watch=False, silent=True)
934
+ build_project(project=project, tb_client=client, watch=False, config=config, silent=True)
935
935
  click.echo(FeedbackManager.success(message="✓ Build completed!"))
936
936
  connections = client.connections("kafka")
937
937
 
@@ -1209,7 +1209,7 @@ STEP 3: ADD KEY TO SERVICE ACCOUNT
1209
1209
 
1210
1210
  debug_running_file = print_message("** Running {file}", bcolors.CGREY)
1211
1211
 
1212
- highlight_building_project = info_highlight_message("\n» Building project...")
1212
+ highlight_building_project = info_highlight_message("» Building project...")
1213
1213
 
1214
1214
  success = success_message("{message}")
1215
1215
  info = info_message("{message}")
@@ -5,6 +5,7 @@ import os
5
5
  import re
6
6
  import subprocess
7
7
  import time
8
+ import uuid
8
9
  from typing import Any, Dict, Optional
9
10
 
10
11
  import boto3
@@ -56,6 +57,17 @@ def get_tinybird_local_config(config_obj: Dict[str, Any], test: bool = False, si
56
57
  if path:
57
58
  user_client = config.get_client(host=TB_LOCAL_ADDRESS, token=user_token)
58
59
  if test:
60
+ # delete any Tinybird_Local_Test_* workspace
61
+ user_workspaces = requests.get(
62
+ f"{TB_LOCAL_ADDRESS}/v1/user/workspaces?with_organization=true&token={admin_token}"
63
+ ).json()
64
+ local_workspaces = user_workspaces.get("workspaces", [])
65
+ for ws in local_workspaces:
66
+ if ws["name"].startswith("Tinybird_Local_Test_"):
67
+ requests.delete(
68
+ f"{TB_LOCAL_ADDRESS}/v1/workspaces/{ws['id']}?token={user_token}&hard_delete_confirmation=yes"
69
+ )
70
+
59
71
  ws_name = get_test_workspace_name(path)
60
72
  else:
61
73
  ws_name = config.get("name") or config_obj.get("name") or get_build_workspace_name(path)
@@ -104,8 +116,8 @@ def get_build_workspace_name(path: str) -> str:
104
116
 
105
117
 
106
118
  def get_test_workspace_name(path: str) -> str:
107
- folder_hash = hashlib.sha256(path.encode()).hexdigest()
108
- return f"Tinybird_Local_Test_{folder_hash}"
119
+ random_folder_suffix = str(uuid.uuid4()).replace("-", "_")
120
+ return f"Tinybird_Local_Test_{random_folder_suffix}"
109
121
 
110
122
 
111
123
  def get_local_tokens() -> Dict[str, str]:
@@ -3,7 +3,7 @@
3
3
  # - If it makes sense and only when strictly necessary, you can create utility functions in this file.
4
4
  # - But please, **do not** interleave utility functions and command definitions.
5
5
 
6
- from typing import Tuple
6
+ from typing import Any, Tuple
7
7
 
8
8
  import click
9
9
 
@@ -34,7 +34,8 @@ def test_create(ctx: click.Context, name_or_filename: str, prompt: str) -> None:
34
34
  """
35
35
  project: Project = ctx.ensure_object(dict)["project"]
36
36
  client: TinyB = ctx.ensure_object(dict)["client"]
37
- create_test(name_or_filename, prompt, project, client)
37
+ config: dict[str, Any] = ctx.ensure_object(dict)["config"]
38
+ create_test(name_or_filename, prompt, project, client, config=config)
38
39
 
39
40
 
40
41
  @test.command(
@@ -46,7 +47,8 @@ def test_create(ctx: click.Context, name_or_filename: str, prompt: str) -> None:
46
47
  def test_update(ctx: click.Context, pipe: str) -> None:
47
48
  client: TinyB = ctx.ensure_object(dict)["client"]
48
49
  project: Project = ctx.ensure_object(dict)["project"]
49
- update_test(pipe, project, client)
50
+ config: dict[str, Any] = ctx.ensure_object(dict)["config"]
51
+ update_test(pipe, project, client, config=config)
50
52
 
51
53
 
52
54
  @test.command(
@@ -58,4 +60,5 @@ def test_update(ctx: click.Context, pipe: str) -> None:
58
60
  def run_tests_command(ctx: click.Context, name: Tuple[str, ...]) -> None:
59
61
  client: TinyB = ctx.ensure_object(dict)["client"]
60
62
  project: Project = ctx.ensure_object(dict)["project"]
61
- run_tests(name, project, client)
63
+ config: dict[str, Any] = ctx.ensure_object(dict)["config"]
64
+ run_tests(name, project, client, config=config)
@@ -18,7 +18,6 @@ from tinybird.prompts import test_create_prompt
18
18
  from tinybird.tb.client import TinyB
19
19
  from tinybird.tb.modules.build_common import process as build_project
20
20
  from tinybird.tb.modules.common import sys_exit
21
- from tinybird.tb.modules.config import CLIConfig
22
21
  from tinybird.tb.modules.exceptions import CLITestException
23
22
  from tinybird.tb.modules.feedback_manager import FeedbackManager
24
23
  from tinybird.tb.modules.llm import LLM
@@ -55,7 +54,7 @@ def generate_test_file(pipe_name: str, tests: List[Dict[str, Any]], folder: Opti
55
54
 
56
55
 
57
56
  def create_test(
58
- name_or_filename: str, prompt: str, project: Project, client: TinyB, preview: bool = False
57
+ name_or_filename: str, prompt: str, project: Project, client: TinyB, config: dict[str, Any], preview: bool = False
59
58
  ) -> list[dict[str, Any]]:
60
59
  """
61
60
  Create a test for an existing pipe
@@ -64,11 +63,12 @@ def create_test(
64
63
 
65
64
  try:
66
65
  click.echo(FeedbackManager.highlight(message="\n» Building test environment"))
67
- build_error = build_project(project=project, tb_client=client, watch=False, silent=True, exit_on_error=False)
66
+ build_error = build_project(
67
+ project=project, tb_client=client, watch=False, silent=True, exit_on_error=False, config=config
68
+ )
68
69
  if build_error:
69
70
  raise Exception(build_error)
70
71
  click.echo(FeedbackManager.info(message="✓ Done!\n"))
71
- config = CLIConfig.get_project_config()
72
72
  folder = project.folder
73
73
  pipe_path = get_pipe_path(name_or_filename, folder)
74
74
  pipe_name = pipe_path.stem
@@ -82,11 +82,11 @@ def create_test(
82
82
  content=pipe_content,
83
83
  parameters=parameters or "No parameters",
84
84
  )
85
- user_token = config.get_user_token()
85
+ user_token = config.get("user_token")
86
86
  if not user_token:
87
87
  raise Exception("No user token found")
88
88
 
89
- llm = LLM(user_token=user_token, host=config.get_client().host)
89
+ llm = LLM(user_token=user_token, host=config.get("host") or "")
90
90
  response_llm = llm.ask(system_prompt=system_prompt, prompt=prompt, feature="tb_test_create")
91
91
  response_xml = extract_xml(response_llm, "response")
92
92
  tests_content = parse_xml(response_xml, "test")
@@ -142,11 +142,13 @@ def dump_tests(tests: List[Dict[str, Any]]) -> str:
142
142
  return yaml_str.replace("- name:", "\n- name:")
143
143
 
144
144
 
145
- def update_test(pipe: str, project: Project, client: TinyB) -> None:
145
+ def update_test(pipe: str, project: Project, client: TinyB, config: dict[str, Any]) -> None:
146
146
  try:
147
147
  folder = project.folder
148
148
  click.echo(FeedbackManager.highlight(message="\n» Building test environment"))
149
- build_error = build_project(project=project, tb_client=client, watch=False, silent=True, exit_on_error=False)
149
+ build_error = build_project(
150
+ project=project, tb_client=client, watch=False, silent=True, exit_on_error=False, config=config
151
+ )
150
152
  if build_error:
151
153
  raise Exception(build_error)
152
154
 
@@ -190,11 +192,18 @@ def update_test(pipe: str, project: Project, client: TinyB) -> None:
190
192
  cleanup_test_workspace(client, project.folder)
191
193
 
192
194
 
193
- def run_tests(name: Tuple[str, ...], project: Project, client: TinyB) -> Optional[str]:
195
+ def run_tests(name: Tuple[str, ...], project: Project, client: TinyB, config: dict[str, Any]) -> Optional[str]:
194
196
  full_error = ""
195
197
  try:
196
198
  click.echo(FeedbackManager.highlight(message="\n» Building test environment"))
197
- build_error = build_project(project=project, tb_client=client, watch=False, silent=True, exit_on_error=False)
199
+ build_error = build_project(
200
+ project=project,
201
+ tb_client=client,
202
+ watch=False,
203
+ silent=True,
204
+ exit_on_error=False,
205
+ config=config,
206
+ )
198
207
  if build_error:
199
208
  raise Exception(build_error)
200
209
  click.echo(FeedbackManager.info(message="✓ Done!"))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev292
3
+ Version: 0.0.1.dev294
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird