tinybird 0.0.1.dev273__tar.gz → 0.0.1.dev275__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 (146) hide show
  1. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/PKG-INFO +1 -1
  2. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/feedback_manager.py +6 -0
  3. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/__cli__.py +2 -2
  4. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/agent.py +2 -2
  5. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/prompts.py +1 -0
  6. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/testing_agent.py +7 -4
  7. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/test.py +109 -1
  8. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/cli.py +1 -1
  9. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/deployment_common.py +21 -5
  10. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/test_common.py +47 -14
  11. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/cli.py +9 -0
  12. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/pipe.py +6 -0
  13. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird.egg-info/PKG-INFO +1 -1
  14. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/setup.cfg +0 -0
  15. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/__cli__.py +0 -0
  16. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/ch_utils/constants.py +0 -0
  17. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/ch_utils/engine.py +0 -0
  18. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/check_pypi.py +0 -0
  19. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/client.py +0 -0
  20. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/config.py +0 -0
  21. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/connectors.py +0 -0
  22. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/context.py +0 -0
  23. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/datafile/common.py +0 -0
  24. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/datafile/exceptions.py +0 -0
  25. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/datafile/parse_connection.py +0 -0
  26. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/datafile/parse_datasource.py +0 -0
  27. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/datafile/parse_pipe.py +0 -0
  28. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/datatypes.py +0 -0
  29. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/git_settings.py +0 -0
  30. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/prompts.py +0 -0
  31. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/sql.py +0 -0
  32. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/sql_template.py +0 -0
  33. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/sql_template_fmt.py +0 -0
  34. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/sql_toolset.py +0 -0
  35. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/syncasync.py +0 -0
  36. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/check_pypi.py +0 -0
  37. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/cli.py +0 -0
  38. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/client.py +0 -0
  39. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/config.py +0 -0
  40. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/__init__.py +0 -0
  41. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/animations.py +0 -0
  42. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/banner.py +0 -0
  43. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/command_agent.py +0 -0
  44. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/compactor.py +0 -0
  45. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/explore_agent.py +0 -0
  46. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/memory.py +0 -0
  47. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/models.py +0 -0
  48. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/__init__.py +0 -0
  49. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/analyze.py +0 -0
  50. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/append.py +0 -0
  51. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/build.py +0 -0
  52. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/datafile.py +0 -0
  53. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/deploy.py +0 -0
  54. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/deploy_check.py +0 -0
  55. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/diff_resource.py +0 -0
  56. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/execute_query.py +0 -0
  57. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/get_endpoint_stats.py +0 -0
  58. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/get_openapi_definition.py +0 -0
  59. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/mock.py +0 -0
  60. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/plan.py +0 -0
  61. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/request_endpoint.py +0 -0
  62. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/run_command.py +0 -0
  63. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/tools/secret.py +0 -0
  64. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/agent/utils.py +0 -0
  65. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/build.py +0 -0
  66. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/build_common.py +0 -0
  67. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/cicd.py +0 -0
  68. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/common.py +0 -0
  69. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/config.py +0 -0
  70. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/connection.py +0 -0
  71. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/copy.py +0 -0
  72. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/create.py +0 -0
  73. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/datafile/build.py +0 -0
  74. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/datafile/build_common.py +0 -0
  75. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  76. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  77. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/datafile/diff.py +0 -0
  78. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/datafile/fixture.py +0 -0
  79. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/datafile/format_common.py +0 -0
  80. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  81. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  82. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  83. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/datafile/playground.py +0 -0
  84. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/datafile/pull.py +0 -0
  85. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/datasource.py +0 -0
  86. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/deployment.py +0 -0
  87. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/deprecations.py +0 -0
  88. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/dev_server.py +0 -0
  89. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/endpoint.py +0 -0
  90. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/exceptions.py +0 -0
  91. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/feedback_manager.py +0 -0
  92. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/info.py +0 -0
  93. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/infra.py +0 -0
  94. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/job.py +0 -0
  95. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/llm.py +0 -0
  96. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/llm_utils.py +0 -0
  97. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/local.py +0 -0
  98. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/local_common.py +0 -0
  99. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/login.py +0 -0
  100. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/login_common.py +0 -0
  101. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/logout.py +0 -0
  102. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/materialization.py +0 -0
  103. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/mock.py +0 -0
  104. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/mock_common.py +0 -0
  105. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/open.py +0 -0
  106. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/pipe.py +0 -0
  107. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/project.py +0 -0
  108. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/regions.py +0 -0
  109. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/secret.py +0 -0
  110. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/secret_common.py +0 -0
  111. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/shell.py +0 -0
  112. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/sink.py +0 -0
  113. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/table.py +0 -0
  114. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/telemetry.py +0 -0
  115. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/test.py +0 -0
  116. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  117. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  118. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/token.py +0 -0
  119. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/watch.py +0 -0
  120. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/workspace.py +0 -0
  121. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb/modules/workspace_members.py +0 -0
  122. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli.py +0 -0
  123. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/auth.py +0 -0
  124. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/branch.py +0 -0
  125. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/cicd.py +0 -0
  126. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/common.py +0 -0
  127. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/config.py +0 -0
  128. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/connection.py +0 -0
  129. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/datasource.py +0 -0
  130. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/exceptions.py +0 -0
  131. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/fmt.py +0 -0
  132. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/job.py +0 -0
  133. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/regions.py +0 -0
  134. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/tag.py +0 -0
  135. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/telemetry.py +0 -0
  136. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/test.py +0 -0
  137. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  138. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  139. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/workspace.py +0 -0
  140. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  141. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird/tornado_template.py +0 -0
  142. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird.egg-info/SOURCES.txt +0 -0
  143. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird.egg-info/dependency_links.txt +0 -0
  144. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird.egg-info/entry_points.txt +0 -0
  145. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/tinybird.egg-info/requires.txt +0 -0
  146. {tinybird-0.0.1.dev273 → tinybird-0.0.1.dev275}/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.dev273
3
+ Version: 0.0.1.dev275
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -598,6 +598,12 @@ Ready? """
598
598
  warning_confirm_delete_branch = prompt_message("Do you want to remove '{branch}' Branch?")
599
599
  warning_confirm_delete_release = prompt_message("Do you want to remove Release {semver}?")
600
600
  warning_confirm_rollback_release = prompt_message("Do you want to rollback current Release {semver} to {rollback}?")
601
+ warning_confirm_on_demand_compute = warning_message(
602
+ "On-demand compute will incur additional costs beyond your regular usage.\n"
603
+ "This feature uses dedicated compute resources that are billed separately.\n"
604
+ "You can read more about the pricing at https://www.tinybird.co/docs/classic/work-with-data/process-and-copy/materialized-views#compute-compute-separation-for-populates\n\n"
605
+ "Do you want to proceed with on-demand compute?"
606
+ )
601
607
 
602
608
  warning_confirm_delete_token = prompt_message("Do you want to delete Token {token}?")
603
609
  warning_confirm_refresh_token = prompt_message("Do you want to refresh Token {token}?")
@@ -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.dev273'
8
- __revision__ = '9f4ea9e'
7
+ __version__ = '0.0.1.dev275'
8
+ __revision__ = '0c15fc3'
@@ -704,9 +704,9 @@ def get_connection_datafile_local(config: dict[str, Any], connection_name: str)
704
704
  return "Connection not found"
705
705
 
706
706
 
707
- def run_tests(client: TinyB, project: Project, pipe_name: Optional[str] = None) -> None:
707
+ def run_tests(client: TinyB, project: Project, pipe_name: Optional[str] = None) -> Optional[str]:
708
708
  try:
709
- run_tests_common(name=(pipe_name,) if pipe_name else (), project=project, client=client)
709
+ return run_tests_common(name=(pipe_name,) if pipe_name else (), project=project, client=client)
710
710
  except SystemExit as e:
711
711
  raise Exception(e.args[0])
712
712
 
@@ -612,6 +612,7 @@ test_instructions = """
612
612
  - MANDATORY: Before creating the test, analyze the fixture files that the tables of the endpoint are using so you can create relevant tests.
613
613
  - IMPORTANT: expected_result field should always be an empty string, because it will be filled by the `create_test` tool.
614
614
  - If the endpoint does not have parameters, you can omit parameters and generate a single test.
615
+ - If some tests are skipped, it is because some test names do not match any pipe name. Rename the test file to match the pipe name.
615
616
  - The format of the test file is the following:
616
617
  <test_file_format>
617
618
  - name: kpis_single_day
@@ -5,8 +5,7 @@ from pydantic_ai.usage import Usage
5
5
  from tinybird.tb.modules.agent.animations import ThinkingAnimation
6
6
  from tinybird.tb.modules.agent.models import create_model
7
7
  from tinybird.tb.modules.agent.prompts import test_instructions, tests_files_prompt, tone_and_style_instructions
8
- from tinybird.tb.modules.agent.tools.test import create_tests as create_tests_tool
9
- from tinybird.tb.modules.agent.tools.test import run_tests as run_tests_tool
8
+ from tinybird.tb.modules.agent.tools.test import create_tests, remove_test, rename_test, run_tests
10
9
  from tinybird.tb.modules.agent.utils import TinybirdAgentContext
11
10
  from tinybird.tb.modules.project import Project
12
11
 
@@ -42,13 +41,17 @@ You can do the following:
42
41
  - Create new test files.
43
42
  - Update existing test files.
44
43
  - Run tests.
44
+ - Rename test files.
45
+ - Remove test files.
45
46
  """,
46
47
  tone_and_style_instructions,
47
48
  test_instructions,
48
49
  ],
49
50
  tools=[
50
- Tool(create_tests_tool, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
51
- Tool(run_tests_tool, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
51
+ Tool(create_tests, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
52
+ Tool(run_tests, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
53
+ Tool(rename_test, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
54
+ Tool(remove_test, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
52
55
  ],
53
56
  )
54
57
 
@@ -1,3 +1,4 @@
1
+ import os
1
2
  from pathlib import Path
2
3
  from typing import Optional
3
4
 
@@ -122,7 +123,6 @@ def run_tests(ctx: RunContext[TinybirdAgentContext], pipe_name: Optional[str] =
122
123
  return f"User did not confirm the proposed changes and gave the following feedback: {feedback}"
123
124
 
124
125
  test_output = ctx.deps.run_tests(pipe_name=pipe_name)
125
- click.echo(test_output)
126
126
  ctx.deps.thinking_animation.start()
127
127
  if pipe_name:
128
128
  return f"Tests for '{pipe_name}' endpoint in {path} and ran successfully\n{test_output}"
@@ -146,3 +146,111 @@ def run_tests(ctx: RunContext[TinybirdAgentContext], pipe_name: Optional[str] =
146
146
  error_message = error_message.replace(test_exit_code, "")
147
147
  ctx.deps.thinking_animation.start()
148
148
  return f"Error running tests: {error_message}"
149
+
150
+
151
+ def rename_test(ctx: RunContext[TinybirdAgentContext], path: str, new_path: str) -> str:
152
+ """Renames a test file.
153
+
154
+ Args:
155
+ path (str): The path to the test file to rename. Required.
156
+ new_path (str): The new path to the test file. Required.
157
+
158
+ Returns:
159
+ str: Result of the rename operation.
160
+ """
161
+ try:
162
+ ctx.deps.thinking_animation.stop()
163
+ confirmation = show_confirmation(
164
+ title=f"Rename '{path}' to '{new_path}'?",
165
+ skip_confirmation=ctx.deps.dangerously_skip_permissions,
166
+ )
167
+
168
+ if confirmation == "review":
169
+ feedback = show_input(ctx.deps.workspace_name)
170
+ ctx.deps.thinking_animation.start()
171
+ return f"User did not confirm the proposed changes and gave the following feedback: {feedback}"
172
+
173
+ click.echo(FeedbackManager.highlight(message=f"» Renaming test file {path} to {new_path}..."))
174
+ old_path_full = Path(ctx.deps.folder) / path.removeprefix("/")
175
+ new_path_full = Path(ctx.deps.folder) / new_path.removeprefix("/")
176
+
177
+ if not old_path_full.exists():
178
+ click.echo(FeedbackManager.error(message=f"Error: Test file {path} not found"))
179
+ ctx.deps.thinking_animation.start()
180
+ return f"Error: Test file {path} not found (double check the file path)"
181
+
182
+ if new_path_full.exists():
183
+ click.echo(FeedbackManager.error(message=f"Error: Test file {new_path} already exists"))
184
+ ctx.deps.thinking_animation.start()
185
+ return f"Error: Test file {new_path} already exists"
186
+
187
+ # Ensure new file has .yaml extension for test files
188
+ if new_path_full.suffix != ".yaml":
189
+ new_path_full = new_path_full.with_suffix(".yaml")
190
+ new_path = str(new_path_full.relative_to(ctx.deps.folder))
191
+
192
+ parent_path = new_path_full.parent
193
+ parent_path.mkdir(parents=True, exist_ok=True)
194
+ os.rename(old_path_full, new_path_full)
195
+
196
+ click.echo(FeedbackManager.success(message=f"✓ {new_path} created"))
197
+ ctx.deps.thinking_animation.start()
198
+ return f"Renamed test file from {path} to {new_path}"
199
+ except AgentRunCancelled as e:
200
+ raise e
201
+ except FileNotFoundError:
202
+ ctx.deps.thinking_animation.start()
203
+ click.echo(FeedbackManager.error(message=f"Error: Test file {path} not found"))
204
+ return f"Error: Test file {path} not found (double check the file path)"
205
+ except Exception as e:
206
+ ctx.deps.thinking_animation.stop()
207
+ click.echo(FeedbackManager.error(message=e))
208
+ ctx.deps.thinking_animation.start()
209
+ return f"Error renaming test file {path} to {new_path}: {e}"
210
+
211
+
212
+ def remove_test(ctx: RunContext[TinybirdAgentContext], path: str) -> str:
213
+ """Removes a test file from the project folder
214
+
215
+ Args:
216
+ path (str): The path to the test file to remove. Required.
217
+
218
+ Returns:
219
+ str: If the test file was removed successfully.
220
+ """
221
+ try:
222
+ ctx.deps.thinking_animation.stop()
223
+ path = path.removeprefix("/")
224
+ full_path = Path(ctx.deps.folder) / path
225
+
226
+ if not full_path.exists():
227
+ click.echo(FeedbackManager.error(message=f"Error: Test file {path} not found"))
228
+ ctx.deps.thinking_animation.start()
229
+ return f"Error: Test file {path} not found (double check the file path)"
230
+
231
+ confirmation = show_confirmation(
232
+ title=f"Delete '{path}'?",
233
+ skip_confirmation=ctx.deps.dangerously_skip_permissions,
234
+ )
235
+
236
+ if confirmation == "review":
237
+ feedback = show_input(ctx.deps.workspace_name)
238
+ ctx.deps.thinking_animation.start()
239
+ return f"User did not confirm the proposed changes and gave the following feedback: {feedback}"
240
+
241
+ click.echo(FeedbackManager.highlight(message=f"» Removing {path}..."))
242
+
243
+ # Remove the test file
244
+ full_path.unlink()
245
+
246
+ click.echo(FeedbackManager.success(message=f"✓ {path} removed"))
247
+ ctx.deps.thinking_animation.start()
248
+
249
+ return f"Removed test file {path}."
250
+ except AgentRunCancelled as e:
251
+ raise e
252
+ except Exception as e:
253
+ ctx.deps.thinking_animation.stop()
254
+ click.echo(FeedbackManager.error(message=e))
255
+ ctx.deps.thinking_animation.start()
256
+ return f"Error removing test file {path}: {e}"
@@ -149,7 +149,7 @@ def cli(
149
149
  if user_token:
150
150
  config_temp.set_user_token(user_token)
151
151
  if token or host or user_token:
152
- try_update_config_with_remote(config_temp, auto_persist=False, raise_on_errors=False)
152
+ try_update_config_with_remote(config_temp, auto_persist=True, raise_on_errors=False)
153
153
 
154
154
  # Overwrite token and host with env vars manually, without resorting to click.
155
155
  #
@@ -19,11 +19,24 @@ from tinybird.tb.modules.project import Project
19
19
 
20
20
 
21
21
  # TODO(eclbg): This should eventually end up in client.py, but we're not using it here yet.
22
- def api_fetch(url: str, headers: dict) -> dict:
23
- r = requests.get(url, headers=headers)
24
- if r.status_code == 200:
25
- logging.debug(json.dumps(r.json(), indent=2))
26
- return r.json()
22
+ def api_fetch(url: str, headers: dict, max_retries: int = 3, backoff_factor: float = 0.5) -> dict:
23
+ retries = 0
24
+ while retries <= max_retries:
25
+ try:
26
+ r = requests.get(url, headers=headers)
27
+ if r.status_code == 200:
28
+ logging.debug(json.dumps(r.json(), indent=2))
29
+ return r.json()
30
+ else:
31
+ raise Exception(f"Request failed with status code {r.status_code}")
32
+ except Exception:
33
+ retries += 1
34
+ if retries > max_retries:
35
+ break
36
+
37
+ wait_time = backoff_factor * (2 ** (retries - 1))
38
+ time.sleep(wait_time)
39
+
27
40
  # Try to parse and print the error from the response
28
41
  try:
29
42
  result = r.json()
@@ -35,6 +48,7 @@ def api_fetch(url: str, headers: dict) -> dict:
35
48
  message = "Error parsing response from API"
36
49
  click.echo(FeedbackManager.error(message=message))
37
50
  sys_exit("deployment_error", message)
51
+
38
52
  return {}
39
53
 
40
54
 
@@ -48,6 +62,7 @@ def api_post(
48
62
  if r.status_code < 300:
49
63
  logging.debug(json.dumps(r.json(), indent=2))
50
64
  return r.json()
65
+
51
66
  # Try to parse and print the error from the response
52
67
  try:
53
68
  result = r.json()
@@ -61,6 +76,7 @@ def api_post(
61
76
  message = "Error parsing response from API"
62
77
  click.echo(FeedbackManager.error(message=message))
63
78
  sys_exit("deployment_error", message)
79
+
64
80
  return {}
65
81
 
66
82
 
@@ -188,7 +188,7 @@ def update_test(pipe: str, project: Project, client: TinyB) -> None:
188
188
  cleanup_test_workspace(client, project.folder)
189
189
 
190
190
 
191
- def run_tests(name: Tuple[str, ...], project: Project, client: TinyB) -> None:
191
+ def run_tests(name: Tuple[str, ...], project: Project, client: TinyB) -> Optional[str]:
192
192
  full_error = ""
193
193
  try:
194
194
  load_secrets(project=project, client=client)
@@ -203,19 +203,30 @@ def run_tests(name: Tuple[str, ...], project: Project, client: TinyB) -> None:
203
203
  endpoints if len(endpoints) > 0 else glob.glob(f"{project.path}/tests/**/*.y*ml", recursive=True)
204
204
  )
205
205
 
206
- def run_test(test_file) -> Optional[str]:
206
+ def run_test(test_file) -> Tuple[Optional[str], int, int, bool]:
207
207
  test_file_path = Path(test_file)
208
- click.echo(FeedbackManager.info(message=f"* {test_file_path.stem}{test_file_path.suffix}"))
209
208
  test_file_content = parse_tests(test_file_path.read_text())
209
+ total_tests = len(test_file_content)
210
+
211
+ # Check if pipe exists before processing any tests
212
+ try:
213
+ client._req(f"/v0/pipes/{test_file_path.stem}")
214
+ click.echo(FeedbackManager.info(message=f"* {test_file_path.stem}{test_file_path.suffix}"))
215
+ except Exception:
216
+ # Entire test file skipped because pipe doesn't exist
217
+ click.echo(FeedbackManager.info(message=f"* {test_file_path.stem}{test_file_path.suffix}"))
218
+ click.echo(
219
+ FeedbackManager.warning(message=f"✗ All tests skipped ({test_file_path.stem}.pipe not found)")
220
+ )
221
+ return None, total_tests, total_tests, True # True indicates file was skipped
222
+
210
223
  test_file_errors = ""
224
+ skipped_count = 0
225
+
211
226
  for test in test_file_content:
212
227
  try:
213
228
  test_params = test["parameters"].split("?")[1] if "?" in test["parameters"] else test["parameters"]
214
- response = None
215
- try:
216
- response = get_pipe_data(client, pipe_name=test_file_path.stem, test_params=test_params)
217
- except Exception:
218
- continue
229
+ response = get_pipe_data(client, pipe_name=test_file_path.stem, test_params=test_params)
219
230
 
220
231
  expected_result = response.text
221
232
  if response.status_code >= 400:
@@ -237,23 +248,45 @@ def run_tests(name: Tuple[str, ...], project: Project, client: TinyB) -> None:
237
248
  except Exception as e:
238
249
  test_file_errors += f"✗ {test['name']} failed\n** Output and expected output are different: \n{e}"
239
250
  click.echo(FeedbackManager.error(message=test_file_errors))
240
- return test_file_errors
241
- return None
251
+ return test_file_errors, skipped_count, total_tests, False
252
+ return None, skipped_count, total_tests, False # False indicates file was not skipped
242
253
 
243
254
  failed_tests_count = 0
255
+ skipped_files_count = 0
256
+ total_tests_count = 0
244
257
  test_count = len(test_files)
245
-
258
+ output = ""
246
259
  for test_file in test_files:
247
- if run_test_error := run_test(test_file):
260
+ run_test_error, skipped_count, individual_tests_count, file_skipped = run_test(test_file)
261
+ total_tests_count += individual_tests_count
262
+
263
+ if file_skipped:
264
+ skipped_files_count += 1
265
+ elif run_test_error:
248
266
  full_error += f"\n{run_test_error}"
249
267
  failed_tests_count += 1
250
268
 
269
+ runnable_files_count = test_count - skipped_files_count
270
+ passed_files_count = runnable_files_count - failed_tests_count
271
+
251
272
  if failed_tests_count:
252
- error = f"\n✗ {test_count - failed_tests_count}/{test_count} passed"
273
+ error = f"\n✗ {passed_files_count}/{runnable_files_count} passed"
274
+ if skipped_files_count > 0:
275
+ error += f" ({skipped_files_count} skipped)"
276
+ output += f"{error}\n"
253
277
  click.echo(FeedbackManager.error(message=error))
254
278
  sys_exit("test_error", full_error)
255
279
  else:
256
- click.echo(FeedbackManager.success(message=f"\n✓ {test_count}/{test_count} passed"))
280
+ if runnable_files_count == 0:
281
+ success_message = "\n✓ No tests to run"
282
+ else:
283
+ success_message = f"\n✓ {runnable_files_count}/{runnable_files_count} passed"
284
+ if skipped_files_count > 0:
285
+ success_message += f" ({skipped_files_count} skipped)"
286
+ message_color = FeedbackManager.success if runnable_files_count > 0 else FeedbackManager.warning
287
+ click.echo(message_color(message=success_message))
288
+ output += f"{success_message}\n"
289
+ return output
257
290
  except Exception as e:
258
291
  raise CLITestException(FeedbackManager.error(message=str(e)))
259
292
  finally:
@@ -643,6 +643,15 @@ async def push(
643
643
  ) -> None:
644
644
  """Push files to Tinybird."""
645
645
 
646
+ # Prompt for confirmation when on-demand compute is requested with populate
647
+ if (
648
+ populate
649
+ and on_demand_compute
650
+ and not click.confirm(FeedbackManager.warning_confirm_on_demand_compute(), default=False)
651
+ ):
652
+ click.echo("Operation cancelled.")
653
+ return
654
+
646
655
  ignore_sql_errors = FeatureFlags.ignore_sql_errors()
647
656
  context.disable_template_security_validation.set(True)
648
657
 
@@ -253,6 +253,12 @@ async def pipe_populate(
253
253
  on_demand_compute: bool,
254
254
  ):
255
255
  """Populate the result of a Materialized Node into the target Materialized View"""
256
+
257
+ # Prompt for confirmation when on-demand compute is requested
258
+ if on_demand_compute and not click.confirm(FeedbackManager.warning_confirm_on_demand_compute(), default=False):
259
+ click.echo("Operation cancelled.")
260
+ return
261
+
256
262
  cl = create_tb_client(ctx)
257
263
 
258
264
  pipe = await cl.pipe(pipe_name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev273
3
+ Version: 0.0.1.dev275
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird