tinybird 3.0.2.dev0__tar.gz → 3.1.0.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/PKG-INFO +1 -1
  2. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/service_datasources.py +1 -0
  3. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/sql_template.py +131 -23
  4. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/__cli__.py +2 -2
  5. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/cli.py +1 -0
  6. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/cli.py +2 -2
  7. tinybird-3.1.0.dev0/tinybird/tb/modules/project_commands.py +53 -0
  8. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird.egg-info/PKG-INFO +1 -1
  9. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird.egg-info/SOURCES.txt +1 -0
  10. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/setup.cfg +0 -0
  11. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/__cli__.py +0 -0
  12. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/ch_utils/constants.py +0 -0
  13. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/ch_utils/engine.py +0 -0
  14. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/check_pypi.py +0 -0
  15. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/client.py +0 -0
  16. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/config.py +0 -0
  17. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/context.py +0 -0
  18. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/datafile/common.py +0 -0
  19. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/datafile/exceptions.py +0 -0
  20. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/datafile/parse_connection.py +0 -0
  21. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/datafile/parse_datasource.py +0 -0
  22. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/datafile/parse_pipe.py +0 -0
  23. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/datatypes.py +0 -0
  24. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/feedback_manager.py +0 -0
  25. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/git_settings.py +0 -0
  26. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/prompts.py +0 -0
  27. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/sql.py +0 -0
  28. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/sql_template_fmt.py +0 -0
  29. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/sql_toolset.py +0 -0
  30. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/syncasync.py +0 -0
  31. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/check_pypi.py +0 -0
  32. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/client.py +0 -0
  33. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/config.py +0 -0
  34. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/__init__.py +0 -0
  35. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/agent.py +0 -0
  36. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/animations.py +0 -0
  37. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/banner.py +0 -0
  38. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/command_agent.py +0 -0
  39. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/compactor.py +0 -0
  40. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/explore_agent.py +0 -0
  41. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/file_agent.py +0 -0
  42. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/memory.py +0 -0
  43. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/mock_agent.py +0 -0
  44. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/models.py +0 -0
  45. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/prompts.py +0 -0
  46. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/testing_agent.py +0 -0
  47. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/__init__.py +0 -0
  48. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/analyze.py +0 -0
  49. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/append.py +0 -0
  50. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/build.py +0 -0
  51. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/datafile.py +0 -0
  52. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/deploy.py +0 -0
  53. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/deploy_check.py +0 -0
  54. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/diff_resource.py +0 -0
  55. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/execute_query.py +0 -0
  56. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/file.py +0 -0
  57. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/get_endpoint_stats.py +0 -0
  58. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/get_openapi_definition.py +0 -0
  59. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/mock.py +0 -0
  60. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/plan.py +0 -0
  61. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/request_endpoint.py +0 -0
  62. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/run_command.py +0 -0
  63. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/secret.py +0 -0
  64. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/tools/test.py +0 -0
  65. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/agent/utils.py +0 -0
  66. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/branch.py +0 -0
  67. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/build.py +0 -0
  68. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/build_common.py +0 -0
  69. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/cicd.py +0 -0
  70. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/common.py +0 -0
  71. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/config.py +0 -0
  72. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/connection.py +0 -0
  73. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/connection_kafka.py +0 -0
  74. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/connection_s3.py +0 -0
  75. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/copy.py +0 -0
  76. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/create.py +0 -0
  77. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/datafile/build.py +0 -0
  78. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/datafile/build_common.py +0 -0
  79. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  80. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  81. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/datafile/diff.py +0 -0
  82. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/datafile/fixture.py +0 -0
  83. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/datafile/format_common.py +0 -0
  84. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/datafile/format_connection.py +0 -0
  85. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  86. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  87. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  88. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/datafile/playground.py +0 -0
  89. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/datafile/pull.py +0 -0
  90. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/datasource.py +0 -0
  91. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/deployment.py +0 -0
  92. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/deployment_common.py +0 -0
  93. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/deprecations.py +0 -0
  94. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/dev_server.py +0 -0
  95. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/endpoint.py +0 -0
  96. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/exceptions.py +0 -0
  97. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/feedback_manager.py +0 -0
  98. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/fmt.py +0 -0
  99. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/info.py +0 -0
  100. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/infra.py +0 -0
  101. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/job.py +0 -0
  102. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/job_common.py +0 -0
  103. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/llm.py +0 -0
  104. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/llm_utils.py +0 -0
  105. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/local.py +0 -0
  106. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/local_common.py +0 -0
  107. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/local_logs.py +0 -0
  108. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/login.py +0 -0
  109. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/login_common.py +0 -0
  110. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/logout.py +0 -0
  111. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/materialization.py +0 -0
  112. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/mock.py +0 -0
  113. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/mock_common.py +0 -0
  114. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/open.py +0 -0
  115. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/pipe.py +0 -0
  116. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/project.py +0 -0
  117. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/regions.py +0 -0
  118. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/secret.py +0 -0
  119. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/secret_common.py +0 -0
  120. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/shell.py +0 -0
  121. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/sink.py +0 -0
  122. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/table.py +0 -0
  123. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/telemetry.py +0 -0
  124. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/test.py +0 -0
  125. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/test_common.py +0 -0
  126. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  127. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  128. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/token.py +0 -0
  129. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/watch.py +0 -0
  130. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/workspace.py +0 -0
  131. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb/modules/workspace_members.py +0 -0
  132. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli.py +0 -0
  133. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/auth.py +0 -0
  134. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/branch.py +0 -0
  135. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/cicd.py +0 -0
  136. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/cli.py +0 -0
  137. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/common.py +0 -0
  138. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/config.py +0 -0
  139. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/connection.py +0 -0
  140. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/datasource.py +0 -0
  141. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/exceptions.py +0 -0
  142. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/fmt.py +0 -0
  143. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/job.py +0 -0
  144. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/pipe.py +0 -0
  145. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/regions.py +0 -0
  146. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/tag.py +0 -0
  147. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/telemetry.py +0 -0
  148. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/test.py +0 -0
  149. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  150. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  151. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/workspace.py +0 -0
  152. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  153. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird/tornado_template.py +0 -0
  154. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird.egg-info/dependency_links.txt +0 -0
  155. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird.egg-info/entry_points.txt +0 -0
  156. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird.egg-info/requires.txt +0 -0
  157. {tinybird-3.0.2.dev0 → tinybird-3.1.0.dev0}/tinybird.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 3.0.2.dev0
3
+ Version: 3.1.0.dev0
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -541,6 +541,7 @@ def get_tinybird_service_datasources() -> List[Dict[str, Any]]:
541
541
  "partition_key": "toYYYYMM(run_validation)",
542
542
  },
543
543
  "columns": [
544
+ {"name": "cluster", "type": "LowCardinality(String)"},
544
545
  {"name": "host", "type": "LowCardinality(String)"},
545
546
  {"name": "version", "type": "LowCardinality(String)"},
546
547
  {"name": "stable_version", "type": "LowCardinality(String)"},
@@ -6,9 +6,8 @@ import re
6
6
  from collections import deque
7
7
  from datetime import datetime
8
8
  from functools import lru_cache
9
- from io import StringIO
10
9
  from json import loads
11
- from typing import Any, Dict, List, Optional, Tuple, Union
10
+ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
12
11
 
13
12
  from tornado import escape
14
13
  from tornado.util import ObjectDict, exec_in, unicode_type
@@ -29,6 +28,7 @@ REQUIRED_PARAM_NOT_DEFINED = "Required parameter is not defined"
29
28
  # Pre-compiled regex patterns for performance
30
29
  _STRING_LINE_NUMBER_RE = re.compile(r"\<string\>:(\d*)")
31
30
  _ARRAY_TYPE_RE = re.compile(r"Array\((\w+)\)")
31
+ _EMBEDDED_TEMPLATE_EXPRESSION_RE = re.compile(r"\{\{(.*?)\}\}")
32
32
 
33
33
 
34
34
  def secret_template_key(secret_name: str) -> str:
@@ -2159,12 +2159,32 @@ def get_var_names_and_types(t, node_id=None):
2159
2159
  [{'name': 'with_value', 'type': 'Float32', 'default': 0.1}]
2160
2160
  >>> get_var_names_and_types(Template("SELECT * FROM filter_value WHERE description = {{String(d, 'test_1')}} AND value = {{Int8(v, 3)}}"))
2161
2161
  [{'name': 'd', 'type': 'String', 'default': 'test_1'}, {'name': 'v', 'type': 'Int8', 'default': 3}]
2162
+ >>> get_var_names_and_types(Template("select * from test {% if defined(number_variable) %} where number_variable = {{UInt64(number_variable)}} {% end %}"))
2163
+ [{'name': 'number_variable', 'type': 'UInt64', 'default': None}]
2162
2164
  >>> get_var_names_and_types(Template("select * from test {% if defined({{UInt64(number_variable)}}) %} where 1 {% end %}"))
2163
2165
  [{'name': 'number_variable', 'type': 'UInt64', 'default': None}]
2164
2166
  >>> get_var_names_and_types(Template("select * from test {% if defined(testing) and defined(testing2) %} where 1 {%end %}"))
2165
2167
  [{'name': 'testing', 'type': 'String', 'default': None, 'used_in': 'function_call'}, {'name': 'testing2', 'type': 'String', 'default': None, 'used_in': 'function_call'}]
2166
2168
  >>> get_var_names_and_types(Template("select * from test {% if defined({{UInt64(number_variable)}}) %} where 1 {% end %}"))
2167
2169
  [{'name': 'number_variable', 'type': 'UInt64', 'default': None}]
2170
+ >>> get_var_names_and_types(Template("select * from test {% if defined({{UInt64(x)}}) and defined(y) %} where 1 {% end %}"))
2171
+ [{'name': 'x', 'type': 'UInt64', 'default': None}, {'name': 'y', 'type': 'String', 'default': None, 'used_in': 'function_call'}]
2172
+ >>> get_var_names_and_types(Template("select * from test {% if defined(y) and x > 0 %} where x = {{UInt64(x)}} {% end %}"))
2173
+ [{'name': 'x', 'type': 'UInt64', 'default': None}, {'name': 'y', 'type': 'String', 'default': None, 'used_in': 'function_call'}]
2174
+ >>> get_var_names_and_types(Template("select * from test {% if defined(y) and defined(z) and x > 0 %} {{UInt64(x)}} {% end %}"))
2175
+ [{'name': 'x', 'type': 'UInt64', 'default': None}, {'name': 'y', 'type': 'String', 'default': None, 'used_in': 'function_call'}, {'name': 'z', 'type': 'String', 'default': None, 'used_in': 'function_call'}]
2176
+ >>> get_var_names_and_types(Template("{% if '{{' in marker %}{{UInt64(x)}}{% end %}"))
2177
+ [{'name': 'x', 'type': 'UInt64', 'default': None}, {'name': 'marker', 'type': 'String', 'default': None}]
2178
+ >>> get_var_names_and_types(Template("{% if a %}1{% elif defined(y) %}{{UInt64(x)}}{% end %}"))
2179
+ [{'name': 'y', 'type': 'String', 'default': None, 'used_in': 'function_call'}, {'name': 'x', 'type': 'UInt64', 'default': None}, {'name': 'a', 'type': 'String', 'default': None}]
2180
+ >>> get_var_names_and_types(Template("{% for x in items %}{{Int32(x, 0)}}{% end %}"))
2181
+ [{'name': 'x', 'type': 'Int32', 'default': 0}, {'name': 'items', 'type': 'String', 'default': None}]
2182
+ >>> get_var_names_and_types(Template("{% while more %}{{UInt64(x)}}{% end %}"))
2183
+ [{'name': 'x', 'type': 'UInt64', 'default': None}, {'name': 'more', 'type': 'String', 'default': None}]
2184
+ >>> get_var_names_and_types(Template("{% set a = Int32(x, 0) %}"))
2185
+ [{'name': 'a', 'type': 'String', 'default': None}, {'name': 'x', 'type': 'Int32', 'default': 0}]
2186
+ >>> get_var_names_and_types(Template("{% try %}{{UInt64(x)}}{% except E as e %}{{e}}{% end %}"))
2187
+ [{'name': 'x', 'type': 'UInt64', 'default': None}, {'name': 'E', 'type': 'String', 'default': None}, {'name': 'e', 'type': 'String', 'default': None}]
2168
2188
  >>> get_var_names_and_types(Template("select {{Array(cod_stock_source_type,'Int16', defined=False)}}"))
2169
2189
  [{'name': 'cod_stock_source_type', 'type': 'Array(Int16)', 'defined': False, 'default': None}]
2170
2190
  >>> get_var_names_and_types(Template("select {{Array(cod_stock_source_type, defined=False)}}"))
@@ -2194,7 +2214,7 @@ def get_var_names_and_types(t, node_id=None):
2194
2214
  >>> get_var_names_and_types(Template("SELECT * FROM filter_value WHERE description = {{Float32(with_value, -0.1)}} AND description = {{Float32(zero, 0)}} AND value = {{Float32(no_default)}}"))
2195
2215
  [{'name': 'with_value', 'type': 'Float32', 'default': -0.1}, {'name': 'zero', 'type': 'Float32', 'default': 0}, {'name': 'no_default', 'type': 'Float32', 'default': None}]
2196
2216
  >>> get_var_names_and_types(Template('''SELECT * FROM abcd WHERE hotel_id <> 0 {% if defined(date_from) %} AND script_created_at > {{DateTime(date_from, '2020-09-09 10:10:10', description="This is a description", required=True)(date_from, '2020-09-09', description="Filter script alert creation date", required=False)}} {% end %}'''))
2197
- [{'name': 'date_from', 'type': 'DateTime', 'description': 'This is a description', 'required': True, 'default': '2020-09-09 10:10:10'}, {'name': 'date_from', 'type': 'DateTime', 'description': 'This is a description', 'required': True, 'default': '2020-09-09 10:10:10'}]
2217
+ [{'name': 'date_from', 'type': 'DateTime', 'description': 'This is a description', 'required': True, 'default': '2020-09-09 10:10:10'}]
2198
2218
  >>> get_var_names_and_types(Template("SELECT * FROM filter_value WHERE symbol = {{Int128(symbol_id, 11111, description='Symbol Id', required=True)}} AND user = {{Int256(user_id, 3555, description='User Id')}}"))
2199
2219
  [{'name': 'symbol_id', 'type': 'Int128', 'description': 'Symbol Id', 'required': True, 'default': 11111}, {'name': 'user_id', 'type': 'Int256', 'description': 'User Id', 'default': 3555}]
2200
2220
  >>> get_var_names_and_types(Template("SELECT now() > {{DateTime64(timestamp, '2020-09-09 10:10:10.000')}}"))
@@ -2205,32 +2225,118 @@ def get_var_names_and_types(t, node_id=None):
2205
2225
  [{'name': 'symbol_id', 'type': 'Int64', 'default': '9223372036854775807'}]
2206
2226
  """
2207
2227
  try:
2228
+ # Recursive helper that traverses the template's parsed chunks and collects
2229
+ # variable data including types and defaults.
2230
+ #
2231
+ # Optimization: Instead of calling x.generate(writer) which generates full
2232
+ # Python code (expensive for large templates), we parse just the statement
2233
+ # and recurse into the body separately.
2234
+ #
2235
+ # Backward compatibility: The original implementation called get_var_data on
2236
+ # full generated code, where type functions (Array, Int32, etc.) would overwrite
2237
+ # variables from defined(). To maintain this behavior, we process body expressions
2238
+ # FIRST to get types, then only add variables from control statements if they
2239
+ # weren't already found in body expressions.
2240
+
2241
+ # Track variable names seen from EXPRESSIONS (not control statements)
2242
+ # Used to prevent control statements from adding variables with wrong types
2243
+ typed_names: set[str] = set()
2244
+
2245
+ statement_wraps: dict[str, Callable[[str], str]] = {
2246
+ "control": lambda statement: f"{statement}: pass",
2247
+ "elif": lambda statement: "if False: pass\n" + statement + ": pass",
2248
+ "except": lambda statement: "try: pass\n" + statement + ": pass",
2249
+ }
2208
2250
 
2209
- def _n(chunks, v):
2210
- for x in chunks:
2211
- if type(x).__name__ == "_ChunkList":
2212
- _n(x.chunks, v)
2213
- elif type(x).__name__ == "_Expression":
2214
- var_data = get_var_data(x.expression, node_id=node_id)
2215
- if var_data:
2216
- v += var_data
2217
- elif type(x).__name__ == "_ControlBlock":
2218
- buffer = StringIO()
2219
- writer = CodeWriter(buffer, t)
2220
- x.generate(writer)
2221
- var_data = get_var_data(buffer.getvalue(), node_id=node_id)
2222
- if var_data:
2223
- v += var_data
2224
- _n(x.body.chunks, v)
2251
+ def parse_statement_code_if_new_vars(statement_code: str, *, skip_names: set[str]) -> list[dict[str, Any]]:
2252
+ """Parse statement code and return variables not already typed by expressions."""
2253
+ try:
2254
+ # `{{...}}` inside `{% ... %}` is not template syntax in Tornado templates.
2255
+ # It becomes Python braces (e.g. set literals), which can hide unrelated vars
2256
+ # in the statement. Strip them so we still parse the rest of the statement.
2257
+ if "{{" in statement_code and "}}" in statement_code:
2258
+ statement_code = _EMBEDDED_TEMPLATE_EXPRESSION_RE.sub("None", statement_code)
2259
+ var_data = get_var_data(statement_code, node_id=node_id)
2260
+ except Exception:
2261
+ return []
2225
2262
 
2226
- var = []
2227
- _n(t.file.body.chunks, var)
2228
- return var
2263
+ if not var_data:
2264
+ return []
2265
+
2266
+ return [vd for vd in var_data if vd["name"] not in skip_names]
2267
+
2268
+ def parse_statement(statement: str, *, wrap: Callable[[str], str] | None) -> list[dict[str, Any]]:
2269
+ """Parse a statement and return variables not already typed by expressions."""
2270
+ statement_expr_names: set[str] = set()
2271
+ vars_out: list[dict[str, Any]] = []
2272
+
2273
+ if "{{" in statement and "}}" in statement:
2274
+ for match in _EMBEDDED_TEMPLATE_EXPRESSION_RE.finditer(statement):
2275
+ expr = match.group(1).strip()
2276
+ if not expr:
2277
+ continue
2278
+ try:
2279
+ var_data = get_var_data(expr, node_id=node_id)
2280
+ except Exception:
2281
+ continue
2282
+
2283
+ if not var_data:
2284
+ continue
2285
+
2286
+ for vd in var_data:
2287
+ # Body expressions win for types; do not add statement-derived typed vars.
2288
+ if vd["name"] in typed_names:
2289
+ continue
2290
+ statement_expr_names.add(vd["name"])
2291
+ vars_out.append(vd)
2292
+
2293
+ statement_code = wrap(statement) if wrap else statement
2294
+ vars_out.extend(
2295
+ parse_statement_code_if_new_vars(statement_code, skip_names=typed_names | statement_expr_names)
2296
+ )
2297
+ return vars_out
2298
+
2299
+ def _n(chunks: list, vars_out: list[dict[str, Any]]) -> None:
2300
+ for x in chunks:
2301
+ kind = type(x).__name__
2302
+ match kind:
2303
+ case "_ChunkList":
2304
+ _n(x.chunks, vars_out)
2305
+
2306
+ case "_Expression":
2307
+ # Template expression like {{Int32(num_val, 0)}} - extract type info
2308
+ var_data = get_var_data(x.expression, node_id=node_id)
2309
+ if var_data:
2310
+ typed_names.update(vd["name"] for vd in var_data)
2311
+ vars_out.extend(var_data)
2312
+
2313
+ case "_ControlBlock":
2314
+ # Process body FIRST to get type functions
2315
+ _n(x.body.chunks, vars_out)
2316
+ # Then parse statement, but only add vars NOT already typed by expressions
2317
+ if x.statement != "try":
2318
+ vars_out.extend(parse_statement(x.statement, wrap=statement_wraps["control"]))
2319
+
2320
+ case "_IntermediateControlBlock":
2321
+ # elif/else/except/finally - only add vars not typed by expressions
2322
+ if x.statement.startswith("elif "):
2323
+ vars_out.extend(parse_statement(x.statement, wrap=statement_wraps["elif"]))
2324
+ elif x.statement.startswith("except "):
2325
+ vars_out.extend(parse_statement(x.statement, wrap=statement_wraps["except"]))
2326
+
2327
+ case "_Statement":
2328
+ # {% set x = ... %}, {% break %}, etc.
2329
+ if x.statement not in ("break", "continue") and "{{" not in x.statement:
2330
+ vars_out.extend(parse_statement(x.statement, wrap=None))
2331
+
2332
+ vars_out: list[dict[str, Any]] = []
2333
+ _n(t.file.body.chunks, vars_out)
2334
+ return vars_out
2229
2335
  except SecurityException as e:
2230
2336
  raise SQLTemplateException(e)
2231
2337
 
2232
2338
 
2233
- @lru_cache(maxsize=512)
2339
+ @lru_cache(maxsize=2**10)
2234
2340
  def get_var_names_and_types_cached(t: Template):
2235
2341
  return get_var_names_and_types(t)
2236
2342
 
@@ -2700,6 +2806,8 @@ def render_sql_template(
2700
2806
  t, template_variables, variable_warnings = get_template_and_variables(
2701
2807
  sql, name, escape_arrays=escape_split_to_array
2702
2808
  )
2809
+
2810
+ ## TODO: Could we skip running this unless we need it for some variable preprocessing?
2703
2811
  template_variables_with_types = get_var_names_and_types_cached(t)
2704
2812
 
2705
2813
  if variables is not None:
@@ -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__ = '3.0.2.dev0'
8
- __revision__ = '5975d81'
7
+ __version__ = '3.1.0.dev0'
8
+ __revision__ = 'a987e5a'
@@ -21,6 +21,7 @@ import tinybird.tb.modules.materialization
21
21
  import tinybird.tb.modules.mock
22
22
  import tinybird.tb.modules.open
23
23
  import tinybird.tb.modules.pipe
24
+ import tinybird.tb.modules.project_commands
24
25
  import tinybird.tb.modules.secret
25
26
  import tinybird.tb.modules.sink
26
27
  import tinybird.tb.modules.test
@@ -5,6 +5,7 @@
5
5
  import json
6
6
  import logging
7
7
  import os
8
+ import re
8
9
  import shutil
9
10
  import sys
10
11
  from os import environ, getcwd
@@ -455,8 +456,6 @@ def ch(ctx: Context, query: str, user: Optional[str], password: Optional[str], m
455
456
 
456
457
 
457
458
  def __patch_click_output():
458
- import re
459
-
460
459
  CUSTOM_PATTERNS: List[str] = []
461
460
 
462
461
  _env_patterns = os.getenv("OBFUSCATE_REGEX_PATTERN", None)
@@ -534,6 +533,7 @@ def create_ctx_client(
534
533
  "diff",
535
534
  "fmt",
536
535
  "init",
536
+ "project",
537
537
  ]
538
538
  command = ctx.invoked_subcommand
539
539
  if not command or command in commands_without_ctx_client:
@@ -0,0 +1,53 @@
1
+ import re
2
+ import tarfile
3
+ from pathlib import Path
4
+ from typing import Optional
5
+
6
+ import click
7
+
8
+ from tinybird.tb.modules.cli import cli
9
+ from tinybird.tb.modules.feedback_manager import FeedbackManager
10
+ from tinybird.tb.modules.project import Project
11
+
12
+
13
+ @cli.group(hidden=True)
14
+ @click.pass_context
15
+ def project(ctx: click.Context) -> None:
16
+ """Project commands."""
17
+
18
+
19
+ @project.command(name="archive")
20
+ @click.option("-o", "--output", type=click.Path(), default=None, help="Output file path")
21
+ @click.pass_context
22
+ def project_archive(ctx: click.Context, output: Optional[str]) -> None:
23
+ """Create a tar.gz archive of all datafiles for support purposes."""
24
+ project_obj: Project = ctx.ensure_object(dict)["project"]
25
+ config = ctx.ensure_object(dict)["config"]
26
+
27
+ all_files = project_obj.get_project_files() + project_obj.get_vendored_files()
28
+
29
+ if not all_files:
30
+ click.echo(FeedbackManager.warning(message="No datafiles found in the project"))
31
+ return
32
+
33
+ if output:
34
+ output_path = Path(output)
35
+ if not output_path.is_absolute():
36
+ output_path = Path(project_obj.folder) / output_path
37
+ else:
38
+ workspace_name = config.get("name", "") or project_obj.workspace_name or "workspace"
39
+ workspace_name = re.sub(r"[^a-zA-Z0-9_-]", "_", workspace_name)
40
+ output_filename = f"{workspace_name}_datafiles.tar.gz"
41
+ output_path = Path(project_obj.folder) / output_filename
42
+
43
+ if output_path.exists() and not click.confirm(f"{output_path} already exists. Overwrite?"):
44
+ click.echo("Aborted.")
45
+ return
46
+
47
+ with tarfile.open(output_path, "w:gz") as tar:
48
+ for f in all_files:
49
+ rel_path = Path(f).relative_to(project_obj.path)
50
+ tar.add(f, arcname=str(rel_path))
51
+ click.echo(f"a {rel_path}")
52
+
53
+ click.echo(FeedbackManager.success(message=f"Created {output_path}"))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 3.0.2.dev0
3
+ Version: 3.1.0.dev0
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -72,6 +72,7 @@ tinybird/tb/modules/mock_common.py
72
72
  tinybird/tb/modules/open.py
73
73
  tinybird/tb/modules/pipe.py
74
74
  tinybird/tb/modules/project.py
75
+ tinybird/tb/modules/project_commands.py
75
76
  tinybird/tb/modules/regions.py
76
77
  tinybird/tb/modules/secret.py
77
78
  tinybird/tb/modules/secret_common.py
File without changes