tinybird 0.0.1.dev258__tar.gz → 0.0.1.dev259__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 (142) hide show
  1. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/PKG-INFO +1 -1
  2. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/prompts.py +1 -0
  3. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/__cli__.py +2 -2
  4. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/agent.py +14 -0
  5. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/prompts.py +35 -3
  6. tinybird-0.0.1.dev259/tinybird/tb/modules/agent/tools/test.py +120 -0
  7. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/utils.py +1 -0
  8. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/project.py +24 -1
  9. tinybird-0.0.1.dev259/tinybird/tb/modules/test.py +61 -0
  10. tinybird-0.0.1.dev258/tinybird/tb/modules/test.py → tinybird-0.0.1.dev259/tinybird/tb/modules/test_common.py +33 -60
  11. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird.egg-info/PKG-INFO +1 -1
  12. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird.egg-info/SOURCES.txt +2 -0
  13. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/setup.cfg +0 -0
  14. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/__cli__.py +0 -0
  15. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/ch_utils/constants.py +0 -0
  16. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/ch_utils/engine.py +0 -0
  17. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/check_pypi.py +0 -0
  18. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/client.py +0 -0
  19. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/config.py +0 -0
  20. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/connectors.py +0 -0
  21. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/context.py +0 -0
  22. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/datafile/common.py +0 -0
  23. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/datafile/exceptions.py +0 -0
  24. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/datafile/parse_connection.py +0 -0
  25. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/datafile/parse_datasource.py +0 -0
  26. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/datafile/parse_pipe.py +0 -0
  27. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/datatypes.py +0 -0
  28. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/feedback_manager.py +0 -0
  29. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/git_settings.py +0 -0
  30. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/sql.py +0 -0
  31. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/sql_template.py +0 -0
  32. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/sql_template_fmt.py +0 -0
  33. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/sql_toolset.py +0 -0
  34. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/syncasync.py +0 -0
  35. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/check_pypi.py +0 -0
  36. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/cli.py +0 -0
  37. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/client.py +0 -0
  38. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/config.py +0 -0
  39. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/__init__.py +0 -0
  40. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/animations.py +0 -0
  41. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/banner.py +0 -0
  42. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/memory.py +0 -0
  43. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/models.py +0 -0
  44. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/__init__.py +0 -0
  45. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/analyze.py +0 -0
  46. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/append.py +0 -0
  47. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/build.py +0 -0
  48. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/create_datafile.py +0 -0
  49. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/deploy.py +0 -0
  50. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/deploy_check.py +0 -0
  51. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/diff_resource.py +0 -0
  52. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/execute_query.py +0 -0
  53. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/explore.py +0 -0
  54. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/get_endpoint_stats.py +0 -0
  55. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/get_openapi_definition.py +0 -0
  56. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/mock.py +0 -0
  57. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/plan.py +0 -0
  58. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/preview_datafile.py +0 -0
  59. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/agent/tools/request_endpoint.py +0 -0
  60. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/build.py +0 -0
  61. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/build_common.py +0 -0
  62. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/cicd.py +0 -0
  63. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/cli.py +0 -0
  64. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/common.py +0 -0
  65. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/config.py +0 -0
  66. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/connection.py +0 -0
  67. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/copy.py +0 -0
  68. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/create.py +0 -0
  69. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/datafile/build.py +0 -0
  70. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/datafile/build_common.py +0 -0
  71. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  72. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  73. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/datafile/diff.py +0 -0
  74. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/datafile/fixture.py +0 -0
  75. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/datafile/format_common.py +0 -0
  76. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  77. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  78. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  79. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/datafile/playground.py +0 -0
  80. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/datafile/pull.py +0 -0
  81. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/datasource.py +0 -0
  82. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/deployment.py +0 -0
  83. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/deployment_common.py +0 -0
  84. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/deprecations.py +0 -0
  85. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/dev_server.py +0 -0
  86. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/endpoint.py +0 -0
  87. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/exceptions.py +0 -0
  88. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/feedback_manager.py +0 -0
  89. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/info.py +0 -0
  90. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/infra.py +0 -0
  91. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/job.py +0 -0
  92. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/llm.py +0 -0
  93. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/llm_utils.py +0 -0
  94. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/local.py +0 -0
  95. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/local_common.py +0 -0
  96. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/login.py +0 -0
  97. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/login_common.py +0 -0
  98. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/logout.py +0 -0
  99. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/materialization.py +0 -0
  100. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/mock.py +0 -0
  101. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/mock_common.py +0 -0
  102. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/open.py +0 -0
  103. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/pipe.py +0 -0
  104. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/regions.py +0 -0
  105. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/secret.py +0 -0
  106. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/secret_common.py +0 -0
  107. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/shell.py +0 -0
  108. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/sink.py +0 -0
  109. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/table.py +0 -0
  110. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/telemetry.py +0 -0
  111. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  112. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  113. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/token.py +0 -0
  114. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/watch.py +0 -0
  115. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/workspace.py +0 -0
  116. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb/modules/workspace_members.py +0 -0
  117. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli.py +0 -0
  118. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/auth.py +0 -0
  119. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/branch.py +0 -0
  120. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/cicd.py +0 -0
  121. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/cli.py +0 -0
  122. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/common.py +0 -0
  123. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/config.py +0 -0
  124. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/connection.py +0 -0
  125. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/datasource.py +0 -0
  126. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/exceptions.py +0 -0
  127. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/fmt.py +0 -0
  128. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/job.py +0 -0
  129. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/pipe.py +0 -0
  130. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/regions.py +0 -0
  131. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/tag.py +0 -0
  132. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/telemetry.py +0 -0
  133. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/test.py +0 -0
  134. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  135. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  136. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/workspace.py +0 -0
  137. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  138. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird/tornado_template.py +0 -0
  139. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird.egg-info/dependency_links.txt +0 -0
  140. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird.egg-info/entry_points.txt +0 -0
  141. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/tinybird.egg-info/requires.txt +0 -0
  142. {tinybird-0.0.1.dev258 → tinybird-0.0.1.dev259}/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.dev258
3
+ Version: 0.0.1.dev259
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -376,6 +376,7 @@ You are a Tinybird expert. You will be given a pipe containing different nodes w
376
376
  - If there are no parameters, you can omit parameters and generate a single test.
377
377
  - The format of the parameters is the following: ?param1=value1&param2=value2&param3=value3
378
378
  - If some parameters are provided by the user and you need to use them, preserve in the same format as they were provided, like case sensitive.
379
+ - If user provides the current test content, use it to generate the new test content.
379
380
  </instructions>
380
381
 
381
382
  This is an example of a test with parameters:
@@ -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.dev258'
8
- __revision__ = 'ca57848'
7
+ __version__ = '0.0.1.dev259'
8
+ __revision__ = '5b5805f'
@@ -32,6 +32,8 @@ from tinybird.tb.modules.agent.tools.mock import mock
32
32
  from tinybird.tb.modules.agent.tools.plan import plan
33
33
  from tinybird.tb.modules.agent.tools.preview_datafile import preview_datafile
34
34
  from tinybird.tb.modules.agent.tools.request_endpoint import request_endpoint
35
+ from tinybird.tb.modules.agent.tools.test import create_tests as create_tests_tool
36
+ from tinybird.tb.modules.agent.tools.test import run_tests as run_tests_tool
35
37
  from tinybird.tb.modules.agent.utils import AgentRunCancelled, TinybirdAgentContext, show_input
36
38
  from tinybird.tb.modules.build_common import process as build_process
37
39
  from tinybird.tb.modules.common import _analyze, _get_tb_client, echo_safe_humanfriendly_tables_format_pretty_table
@@ -43,6 +45,7 @@ from tinybird.tb.modules.local_common import get_tinybird_local_client
43
45
  from tinybird.tb.modules.login_common import login
44
46
  from tinybird.tb.modules.mock_common import append_mock_data, create_mock_data
45
47
  from tinybird.tb.modules.project import Project
48
+ from tinybird.tb.modules.test_common import run_tests as run_tests_common
46
49
 
47
50
 
48
51
  class TinybirdAgent:
@@ -93,6 +96,8 @@ class TinybirdAgent:
93
96
  Tool(execute_query, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
94
97
  Tool(request_endpoint, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
95
98
  Tool(diff_resource, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
99
+ Tool(create_tests_tool, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
100
+ Tool(run_tests_tool, docstring_format="google", require_parameter_descriptions=True, takes_ctx=True),
96
101
  ],
97
102
  # history_processors=[self._keep_recent_messages],
98
103
  )
@@ -152,6 +157,7 @@ class TinybirdAgent:
152
157
  get_connection_datafile_cloud=partial(get_connection_datafile_cloud, config=config),
153
158
  get_connection_datafile_local=partial(get_connection_datafile_local, config=config),
154
159
  get_project_files=project.get_project_files,
160
+ run_tests=partial(run_tests, project=project, config=config),
155
161
  folder=folder,
156
162
  thinking_animation=self.thinking_animation,
157
163
  workspace_name=self.project.workspace_name,
@@ -495,3 +501,11 @@ def get_connection_datafile_local(config: dict[str, Any], connection_name: str)
495
501
  return local_client.connection_file(connection_name)
496
502
  except Exception:
497
503
  return "Connection not found"
504
+
505
+
506
+ def run_tests(config: dict[str, Any], project: Project, pipe_name: Optional[str] = None) -> None:
507
+ local_client = get_tinybird_local_client(config, test=True, silent=True)
508
+ try:
509
+ run_tests_common(name=(pipe_name,) if pipe_name else (), project=project, client=local_client)
510
+ except SystemExit as e:
511
+ raise Exception(e.args[0])
@@ -16,6 +16,7 @@ from tinybird.prompts import (
16
16
  pipe_instructions,
17
17
  s3_connection_example,
18
18
  sink_pipe_instructions,
19
+ test_instructions,
19
20
  )
20
21
  from tinybird.tb.modules.project import Project
21
22
 
@@ -114,6 +115,7 @@ datafile_instructions = """
114
115
  def resources_prompt(project: Project) -> str:
115
116
  files = project.get_project_files()
116
117
  fixture_files = project.get_fixture_files()
118
+ test_files = project.get_test_files()
117
119
 
118
120
  resources_content = "# Existing resources in the project:\n"
119
121
  if files:
@@ -146,7 +148,22 @@ def resources_prompt(project: Project) -> str:
146
148
  else:
147
149
  fixture_content += "No fixture files found"
148
150
 
149
- return resources_content + "\n" + fixture_content
151
+ test_content = "# Test files in the project:\n"
152
+ if test_files:
153
+ tests: list[dict[str, Any]] = []
154
+ for filename in test_files:
155
+ file_path = Path(filename)
156
+ test = {
157
+ "path": str(file_path.relative_to(project.folder)),
158
+ "name": file_path.stem,
159
+ "content": file_path.read_text(),
160
+ }
161
+ tests.append(test)
162
+ test_content = format_as_xml(tests, root_tag="tests", item_tag="test")
163
+ else:
164
+ test_content += "No test files found"
165
+
166
+ return resources_content + "\n" + fixture_content + "\n" + test_content
150
167
 
151
168
 
152
169
  def get_resource_type(path: Path) -> str:
@@ -550,6 +567,7 @@ You have access to the following tools:
550
567
  13. `execute_query` - Execute a query against Tinybird Cloud or Local.
551
568
  13. `request_endpoint` - Request an endpoint against Tinybird Cloud or Local.
552
569
  14. `diff_resource` - Diff the content of a resource in Tinybird Cloud vs Tinybird Local vs Project local file.
570
+ 15. `create_tests` - Create tests for an endpoint.
553
571
 
554
572
  # When creating or updating datafiles:
555
573
  1. Use `plan` tool to plan the creation or update of resources.
@@ -612,22 +630,26 @@ Kafka: {kafka_connection_example}
612
630
  S3: {s3_connection_example}
613
631
  GCS: {gcs_connection_example}
614
632
 
615
- # When executing a query or requesting/testing an endpoint:
633
+ # When executing a query or calling an endpoint:
616
634
  - You need to be sure that the selected resource is updated to the last version in the environment you are working on.
617
635
  - Use `diff_resource` tool to compare the content of the resource to compare the differences between environments.
618
636
  - Project local file is the source of truth.
619
637
  - If the resource is not present or updated to the last version in Tinybird Local, it means you need to build the project.
620
638
  - If the resource is not present or updated to the last version in Tinybird Cloud, it means you need to deploy the project.
639
+ - If exploring an endpoint, the response is empty. You can query the tables to understand what data is available.
640
+
621
641
 
622
642
  # How to use apppend tools:
623
643
  - Use append as part of the creation of a new landing datasource if the user provided a file or an external url
624
644
  - Use append if user explicitly asks for it
625
- - Do not append data if user requests to test an endpoint
645
+ - Do not append data if user requests to test an endpoint or call an endpoint.
646
+ - Do not append data as consequence of an empty response from the endpoint or a query.
626
647
 
627
648
  # How to use `mock` tool:
628
649
  - Use `mock` tool as part of the creation of a new landing datasource if the user did not provided a file or an external url
629
650
  - Use `mock` tool if user explicitly asks for it
630
651
  - Do not use `mock` tool if user requests to test an endpoint.
652
+ - Do not use `mock` tool as consequence of an empty response from the endpoint or a query.
631
653
 
632
654
  # When sharing endpoints paths or urls:
633
655
  - Use `get_openapi_definition` tool to get the url of the endpoint and parameters available.
@@ -639,6 +661,16 @@ GCS: {gcs_connection_example}
639
661
  - `DateTime` parameters accept values in format `YYYY-MM-DD HH:MM:SS`
640
662
  - `Date` parameters accept values in format `YYYYMMDD`
641
663
 
664
+ # Working with tests:
665
+ {test_instructions}
666
+ <dev_notes>
667
+ - Create tests only when the user explicitly asks for it with prompts like "Create tests for this endpoint" or "Create tests for this pipe".
668
+ - If the user asks for "testing an endpoint" or "call an endpoint", just request to the endpoint.
669
+ - The data that the tests are using is the data provided in the fixtures folder.
670
+ - Querying data or requesting endpoints won't return the data that the tests are using.
671
+ - MANDATORY: Before creating the test, analyze the fixture files that the tables of the endpoint are using so you can create relevant tests.
672
+ </dev_notes>
673
+
642
674
  # Info
643
675
  Today is {datetime.now().strftime("%Y-%m-%d")}
644
676
  """
@@ -0,0 +1,120 @@
1
+ from pathlib import Path
2
+ from typing import Optional
3
+
4
+ import click
5
+ from pydantic_ai import RunContext
6
+
7
+ from tinybird.tb.modules.agent.utils import (
8
+ AgentRunCancelled,
9
+ TinybirdAgentContext,
10
+ create_terminal_box,
11
+ show_confirmation,
12
+ show_input,
13
+ )
14
+ from tinybird.tb.modules.feedback_manager import FeedbackManager
15
+
16
+
17
+ def create_tests(ctx: RunContext[TinybirdAgentContext], pipe_name: str, test_content: str) -> str:
18
+ """Given a pipe name, create or update a test for it
19
+
20
+ Args:
21
+ pipe_name (str): The pipe name to create a test for. Required.
22
+ test_content (str): The content of the test. Required.
23
+
24
+ Returns:
25
+ str: If the test was created or updated and the result of running the tests.
26
+ """
27
+ running_tests = False
28
+ try:
29
+ ctx.deps.thinking_animation.stop()
30
+ path = Path(ctx.deps.folder) / "tests" / f"{pipe_name}.yaml"
31
+ current_test_content: Optional[str] = None
32
+ if path.exists():
33
+ current_test_content = path.read_text()
34
+
35
+ if current_test_content:
36
+ content = create_terminal_box(current_test_content, new_content=test_content, title=path.name)
37
+ else:
38
+ content = create_terminal_box(test_content, title=path.name)
39
+
40
+ click.echo(content)
41
+ action_text = "Create" if not current_test_content else "Update"
42
+ confirmation = show_confirmation(
43
+ title=f"{action_text} '{path.name}'?",
44
+ skip_confirmation=ctx.deps.dangerously_skip_permissions,
45
+ )
46
+
47
+ if confirmation == "review":
48
+ feedback = show_input(ctx.deps.workspace_name)
49
+ ctx.deps.thinking_animation.start()
50
+ return f"User did not confirm the proposed changes and gave the following feedback: {feedback}"
51
+
52
+ folder_path = path.parent
53
+ folder_path.mkdir(parents=True, exist_ok=True)
54
+ path.touch(exist_ok=True)
55
+ path.write_text(test_content)
56
+ action_text = "created" if not current_test_content else "updated"
57
+ click.echo(FeedbackManager.success(message=f"✓ {path.name} {action_text}"))
58
+ running_tests = True
59
+ test_output = ctx.deps.run_tests(pipe_name=pipe_name)
60
+ click.echo(test_output)
61
+ ctx.deps.thinking_animation.start()
62
+ return f"Test {action_text} for '{pipe_name}' endpoint in {path} and ran successfully\n{test_output}"
63
+ except AgentRunCancelled as e:
64
+ raise e
65
+ except Exception as e:
66
+ error_message = str(e).replace("test_error__error__", "")
67
+ ctx.deps.thinking_animation.stop()
68
+ if not running_tests:
69
+ click.echo(FeedbackManager.error(message=error_message))
70
+ ctx.deps.thinking_animation.start()
71
+ if running_tests:
72
+ return f"Test {action_text} for '{pipe_name}' endpoint in {path} but there were errors running the tests: {error_message}"
73
+ return f"Error creating test for '{pipe_name}' endpoint: {error_message}"
74
+
75
+
76
+ def run_tests(ctx: RunContext[TinybirdAgentContext], pipe_name: Optional[str] = None) -> str:
77
+ """Run tests for a given pipe name or all tests in the project
78
+
79
+ Args:
80
+ pipe_name (Optional[str]): The pipe name to run tests for. If not provided, all tests in the project will be run.
81
+
82
+ Returns:
83
+ str: The result of running the tests.
84
+ """
85
+
86
+ try:
87
+ ctx.deps.thinking_animation.stop()
88
+ path = Path(ctx.deps.folder) / "tests" / f"{pipe_name}.yaml"
89
+
90
+ title = f"Run tests for '{pipe_name}'?" if pipe_name else "Run all tests in the project?"
91
+ confirmation = show_confirmation(
92
+ title=title,
93
+ skip_confirmation=ctx.deps.dangerously_skip_permissions,
94
+ )
95
+
96
+ if confirmation == "review":
97
+ feedback = show_input(ctx.deps.workspace_name)
98
+ ctx.deps.thinking_animation.start()
99
+ return f"User did not confirm the proposed changes and gave the following feedback: {feedback}"
100
+
101
+ test_output = ctx.deps.run_tests(pipe_name=pipe_name)
102
+ click.echo(test_output)
103
+ ctx.deps.thinking_animation.start()
104
+ if pipe_name:
105
+ return f"Tests for '{pipe_name}' endpoint in {path} and ran successfully\n{test_output}"
106
+ else:
107
+ return f"All tests in the project ran successfully\n{test_output}"
108
+ except AgentRunCancelled as e:
109
+ raise e
110
+ except Exception as e:
111
+ error_message = str(e)
112
+ test_exit_code = "test_error__error__"
113
+ test_error = test_exit_code in error_message
114
+ ctx.deps.thinking_animation.stop()
115
+ if not test_error:
116
+ click.echo(FeedbackManager.error(message=error_message))
117
+ else:
118
+ error_message = error_message.replace(test_exit_code, "")
119
+ ctx.deps.thinking_animation.start()
120
+ return f"Error running tests: {error_message}"
@@ -52,6 +52,7 @@ class TinybirdAgentContext(BaseModel):
52
52
  get_pipe_datafile_local: Callable[..., str]
53
53
  get_connection_datafile_cloud: Callable[..., str]
54
54
  get_connection_datafile_local: Callable[..., str]
55
+ run_tests: Callable[..., Optional[str]]
55
56
  dangerously_skip_permissions: bool
56
57
  token: str
57
58
  user_token: str
@@ -24,6 +24,10 @@ class Project:
24
24
  def vendor_path(self) -> str:
25
25
  return f"{self.path}/vendor"
26
26
 
27
+ @property
28
+ def tests_path(self) -> str:
29
+ return f"{self.path}/tests"
30
+
27
31
  def get_files(self, extension: str) -> List[str]:
28
32
  project_files: List[str] = []
29
33
  for level in range(self.max_depth):
@@ -52,13 +56,32 @@ class Project:
52
56
 
53
57
  def get_fixture_files(self) -> List[str]:
54
58
  fixture_files: List[str] = []
55
- for extension in ["csv", "ndjson", "parquet"]:
59
+ for extension in [
60
+ "csv",
61
+ "csv.gz",
62
+ "ndjson",
63
+ "ndjson.gz",
64
+ "jsonl",
65
+ "jsonl.gz",
66
+ "json",
67
+ "json.gz",
68
+ "parquet",
69
+ "parquet.gz",
70
+ ]:
56
71
  for fixture_file in self.get_files(extension):
57
72
  if self.vendor_path in fixture_file:
58
73
  continue
59
74
  fixture_files.append(fixture_file)
60
75
  return fixture_files
61
76
 
77
+ def get_test_files(self) -> List[str]:
78
+ test_files: List[str] = []
79
+ for test_file in self.get_files("yaml"):
80
+ if self.vendor_path in test_file or self.tests_path not in test_file:
81
+ continue
82
+ test_files.append(test_file)
83
+ return test_files
84
+
62
85
  def get_resource_path(self, resource_name: str, resource_type: str) -> str:
63
86
  full_path = next(
64
87
  (p for p in self.get_project_files() if p.endswith("/" + resource_name + f".{resource_type}")), ""
@@ -0,0 +1,61 @@
1
+ # This is a command file for our CLI. Please keep it clean.
2
+ #
3
+ # - If it makes sense and only when strictly necessary, you can create utility functions in this file.
4
+ # - But please, **do not** interleave utility functions and command definitions.
5
+
6
+ from typing import Tuple
7
+
8
+ import click
9
+
10
+ from tinybird.tb.client import TinyB
11
+ from tinybird.tb.modules.cli import cli
12
+ from tinybird.tb.modules.project import Project
13
+ from tinybird.tb.modules.test_common import create_test, run_tests, update_test
14
+
15
+
16
+ @cli.group()
17
+ @click.pass_context
18
+ def test(ctx: click.Context) -> None:
19
+ """Test commands."""
20
+
21
+
22
+ @test.command(
23
+ name="create",
24
+ help="Create a test for an existing pipe",
25
+ )
26
+ @click.argument("name_or_filename", type=str)
27
+ @click.option(
28
+ "--prompt", type=str, default="Create a test for the selected pipe", help="Prompt to be used to create the test"
29
+ )
30
+ @click.pass_context
31
+ def test_create(ctx: click.Context, name_or_filename: str, prompt: str) -> None:
32
+ """
33
+ Create a test for an existing pipe
34
+ """
35
+ project: Project = ctx.ensure_object(dict)["project"]
36
+ client: TinyB = ctx.ensure_object(dict)["client"]
37
+ create_test(name_or_filename, prompt, project, client)
38
+
39
+
40
+ @test.command(
41
+ name="update",
42
+ help="Update the test expectations for a file or a test.",
43
+ )
44
+ @click.argument("pipe", type=str)
45
+ @click.pass_context
46
+ def test_update(ctx: click.Context, pipe: str) -> None:
47
+ client: TinyB = ctx.ensure_object(dict)["client"]
48
+ project: Project = ctx.ensure_object(dict)["project"]
49
+ update_test(pipe, project, client)
50
+
51
+
52
+ @test.command(
53
+ name="run",
54
+ help="Run the test suite, a file, or a test",
55
+ )
56
+ @click.argument("name", nargs=-1)
57
+ @click.pass_context
58
+ def run_tests_command(ctx: click.Context, name: Tuple[str, ...]) -> None:
59
+ client: TinyB = ctx.ensure_object(dict)["client"]
60
+ project: Project = ctx.ensure_object(dict)["project"]
61
+ run_tests(name, project, client)
@@ -5,7 +5,6 @@
5
5
 
6
6
  import difflib
7
7
  import glob
8
- import sys
9
8
  import urllib.parse
10
9
  from copy import deepcopy
11
10
  from pathlib import Path
@@ -17,8 +16,8 @@ from requests import Response
17
16
 
18
17
  from tinybird.prompts import test_create_prompt
19
18
  from tinybird.tb.client import TinyB
20
- from tinybird.tb.modules.build import process as build_project
21
- from tinybird.tb.modules.cli import cli
19
+ from tinybird.tb.modules.build_common import process as build_project
20
+ from tinybird.tb.modules.common import sys_exit
22
21
  from tinybird.tb.modules.config import CLIConfig
23
22
  from tinybird.tb.modules.exceptions import CLITestException
24
23
  from tinybird.tb.modules.feedback_manager import FeedbackManager
@@ -56,30 +55,17 @@ def generate_test_file(pipe_name: str, tests: List[Dict[str, Any]], folder: Opti
56
55
  return path
57
56
 
58
57
 
59
- @cli.group()
60
- @click.pass_context
61
- def test(ctx: click.Context) -> None:
62
- """Test commands."""
63
-
64
-
65
- @test.command(
66
- name="create",
67
- help="Create a test for an existing pipe",
68
- )
69
- @click.argument("name_or_filename", type=str)
70
- @click.option(
71
- "--prompt", type=str, default="Create a test for the selected pipe", help="Prompt to be used to create the test"
72
- )
73
- @click.pass_context
74
- def test_create(ctx: click.Context, name_or_filename: str, prompt: str) -> None:
58
+ def create_test(
59
+ name_or_filename: str, prompt: str, project: Project, client: TinyB, preview: bool = False
60
+ ) -> list[dict[str, Any]]:
75
61
  """
76
62
  Create a test for an existing pipe
77
63
  """
64
+ tests: List[Dict[str, Any]] = []
65
+
78
66
  try:
79
- project: Project = ctx.ensure_object(dict)["project"]
80
- client: TinyB = ctx.ensure_object(dict)["client"]
81
67
  load_secrets(project=project, client=client)
82
- click.echo(FeedbackManager.highlight(message="\n» Building project"))
68
+ click.echo(FeedbackManager.highlight(message="\n» Building test environment"))
83
69
  build_project(project=project, tb_client=client, watch=False, silent=True)
84
70
  click.echo(FeedbackManager.info(message="✓ Done!\n"))
85
71
  config = CLIConfig.get_project_config()
@@ -105,8 +91,6 @@ def test_create(ctx: click.Context, name_or_filename: str, prompt: str) -> None:
105
91
  response_xml = extract_xml(response_llm, "response")
106
92
  tests_content = parse_xml(response_xml, "test")
107
93
 
108
- tests: List[Dict[str, Any]] = []
109
-
110
94
  for test_content in tests_content:
111
95
  test: Dict[str, Any] = {}
112
96
  test["name"] = extract_xml(test_content, "name")
@@ -131,34 +115,29 @@ def test_create(ctx: click.Context, name_or_filename: str, prompt: str) -> None:
131
115
 
132
116
  tests.append(test)
133
117
 
134
- if len(tests) > 0:
135
- generate_test_file(pipe_name, tests, folder, mode="a")
136
- for test in tests:
137
- test_name = test["name"]
138
- click.echo(FeedbackManager.info(message=f"✓ {test_name} created"))
139
- else:
140
- click.echo(FeedbackManager.info(message="* No tests created"))
118
+ if not preview:
119
+ if len(tests) > 0:
120
+ generate_test_file(pipe_name, tests, folder, mode="a")
121
+ for test in tests:
122
+ test_name = test["name"]
123
+ click.echo(FeedbackManager.info(message=f"✓ {test_name} created"))
124
+ else:
125
+ click.echo(FeedbackManager.info(message="* No tests created"))
141
126
 
142
- click.echo(FeedbackManager.success(message="✓ Done!\n"))
127
+ click.echo(FeedbackManager.success(message="✓ Done!\n"))
143
128
  except Exception as e:
144
129
  raise CLITestException(FeedbackManager.error(message=str(e)))
145
130
  finally:
146
131
  cleanup_test_workspace(client, project.folder)
147
132
 
133
+ return tests
148
134
 
149
- @test.command(
150
- name="update",
151
- help="Update the test expectations for a file or a test.",
152
- )
153
- @click.argument("pipe", type=str)
154
- @click.pass_context
155
- def test_update(ctx: click.Context, pipe: str) -> None:
135
+
136
+ def update_test(pipe: str, project: Project, client: TinyB) -> None:
156
137
  try:
157
- client: TinyB = ctx.ensure_object(dict)["client"]
158
- project: Project = ctx.ensure_object(dict)["project"]
159
138
  folder = project.folder
160
139
  load_secrets(project=project, client=client)
161
- click.echo(FeedbackManager.highlight(message="\n» Building project"))
140
+ click.echo(FeedbackManager.highlight(message="\n» Building test environment"))
162
141
  build_project(project=project, tb_client=client, watch=False, silent=True)
163
142
  click.echo(FeedbackManager.info(message="✓ Done!"))
164
143
  pipe_tests_path = get_pipe_path(pipe, folder)
@@ -200,18 +179,11 @@ def test_update(ctx: click.Context, pipe: str) -> None:
200
179
  cleanup_test_workspace(client, project.folder)
201
180
 
202
181
 
203
- @test.command(
204
- name="run",
205
- help="Run the test suite, a file, or a test",
206
- )
207
- @click.argument("name", nargs=-1)
208
- @click.pass_context
209
- def run_tests(ctx: click.Context, name: Tuple[str, ...]) -> None:
182
+ def run_tests(name: Tuple[str, ...], project: Project, client: TinyB) -> None:
183
+ full_error = ""
210
184
  try:
211
- client: TinyB = ctx.ensure_object(dict)["client"]
212
- project: Project = ctx.ensure_object(dict)["project"]
213
185
  load_secrets(project=project, client=client)
214
- click.echo(FeedbackManager.highlight(message="\n» Building project"))
186
+ click.echo(FeedbackManager.highlight(message="\n» Building test environment"))
215
187
  build_project(project=project, tb_client=client, watch=False, silent=True)
216
188
  click.echo(FeedbackManager.info(message="✓ Done!"))
217
189
 
@@ -222,11 +194,11 @@ def run_tests(ctx: click.Context, name: Tuple[str, ...]) -> None:
222
194
  endpoints if len(endpoints) > 0 else glob.glob(f"{project.path}/tests/**/*.y*ml", recursive=True)
223
195
  )
224
196
 
225
- def run_test(test_file):
197
+ def run_test(test_file) -> Optional[str]:
226
198
  test_file_path = Path(test_file)
227
199
  click.echo(FeedbackManager.info(message=f"* {test_file_path.stem}{test_file_path.suffix}"))
228
200
  test_file_content = yaml.safe_load(test_file_path.read_text())
229
-
201
+ test_file_errors = ""
230
202
  for test in test_file_content:
231
203
  try:
232
204
  test_params = test["parameters"].split("?")[1] if "?" in test["parameters"] else test["parameters"]
@@ -254,22 +226,23 @@ def run_tests(ctx: click.Context, name: Tuple[str, ...]) -> None:
254
226
  )
255
227
  click.echo(FeedbackManager.info(message=f"✓ {test['name']} passed"))
256
228
  except Exception as e:
257
- click.echo(FeedbackManager.error(message=f"✗ {test['name']} failed"))
258
- click.echo(FeedbackManager.error(message=f"\n** Output and expected output are different: \n{e}"))
259
- return False
260
- return True
229
+ test_file_errors += f"✗ {test['name']} failed\n** Output and expected output are different: \n{e}"
230
+ click.echo(FeedbackManager.error(message=test_file_errors))
231
+ return test_file_errors
232
+ return None
261
233
 
262
234
  failed_tests_count = 0
263
235
  test_count = len(test_files)
264
236
 
265
237
  for test_file in test_files:
266
- if not run_test(test_file):
238
+ if run_test_error := run_test(test_file):
239
+ full_error += f"\n{run_test_error}"
267
240
  failed_tests_count += 1
268
241
 
269
242
  if failed_tests_count:
270
243
  error = f"\n✗ {test_count - failed_tests_count}/{test_count} passed"
271
244
  click.echo(FeedbackManager.error(message=error))
272
- sys.exit(1)
245
+ sys_exit("test_error", full_error)
273
246
  else:
274
247
  click.echo(FeedbackManager.success(message=f"\n✓ {test_count}/{test_count} passed"))
275
248
  except Exception as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev258
3
+ Version: 0.0.1.dev259
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -74,6 +74,7 @@ tinybird/tb/modules/sink.py
74
74
  tinybird/tb/modules/table.py
75
75
  tinybird/tb/modules/telemetry.py
76
76
  tinybird/tb/modules/test.py
77
+ tinybird/tb/modules/test_common.py
77
78
  tinybird/tb/modules/token.py
78
79
  tinybird/tb/modules/watch.py
79
80
  tinybird/tb/modules/workspace.py
@@ -102,6 +103,7 @@ tinybird/tb/modules/agent/tools/mock.py
102
103
  tinybird/tb/modules/agent/tools/plan.py
103
104
  tinybird/tb/modules/agent/tools/preview_datafile.py
104
105
  tinybird/tb/modules/agent/tools/request_endpoint.py
106
+ tinybird/tb/modules/agent/tools/test.py
105
107
  tinybird/tb/modules/datafile/build.py
106
108
  tinybird/tb/modules/datafile/build_common.py
107
109
  tinybird/tb/modules/datafile/build_datasource.py