tinybird 0.0.1.dev42__tar.gz → 0.0.1.dev44__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 (104) hide show
  1. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/PKG-INFO +1 -1
  2. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/client.py +1 -1
  3. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/connectors.py +3 -3
  4. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/datafile.py +11 -11
  5. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/feedback_manager.py +1 -1
  6. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/prompts.py +31 -3
  7. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/sql.py +1 -1
  8. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/sql_template_fmt.py +1 -1
  9. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/__cli__.py +2 -2
  10. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/cli.py +1 -1
  11. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/build.py +39 -21
  12. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/cicd.py +2 -2
  13. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/cli.py +8 -61
  14. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/common.py +2 -1
  15. tinybird-0.0.1.dev44/tinybird/tb/modules/copy.py +159 -0
  16. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/create.py +105 -46
  17. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/build.py +64 -247
  18. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datasource.py +1 -1
  19. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/deployment.py +86 -61
  20. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/endpoint.py +90 -3
  21. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/llm_utils.py +2 -2
  22. tinybird-0.0.1.dev44/tinybird/tb/modules/materialization.py +146 -0
  23. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/mock.py +56 -16
  24. tinybird-0.0.1.dev42/tinybird/tb/modules/copy.py → tinybird-0.0.1.dev44/tinybird/tb/modules/pipe.py +14 -11
  25. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/project.py +31 -1
  26. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/test.py +72 -37
  27. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/update.py +1 -1
  28. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/watch.py +54 -5
  29. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/cli.py +1 -1
  30. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/common.py +1 -1
  31. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/pipe.py +1 -1
  32. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +1 -1
  33. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tornado_template.py +2 -2
  34. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird.egg-info/PKG-INFO +1 -1
  35. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird.egg-info/SOURCES.txt +1 -1
  36. tinybird-0.0.1.dev42/tinybird/tb/modules/build_client.py +0 -199
  37. tinybird-0.0.1.dev42/tinybird/tb/modules/pipe.py +0 -480
  38. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/setup.cfg +0 -0
  39. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/__cli__.py +0 -0
  40. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/ch_utils/constants.py +0 -0
  41. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/ch_utils/engine.py +0 -0
  42. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/check_pypi.py +0 -0
  43. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/config.py +0 -0
  44. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/context.py +0 -0
  45. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/datatypes.py +0 -0
  46. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/git_settings.py +0 -0
  47. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/sql_template.py +0 -0
  48. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/sql_toolset.py +0 -0
  49. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/syncasync.py +0 -0
  50. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/auth.py +0 -0
  51. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/config.py +0 -0
  52. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/build_common.py +0 -0
  53. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  54. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  55. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/common.py +0 -0
  56. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/diff.py +0 -0
  57. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/exceptions.py +0 -0
  58. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/fixture.py +0 -0
  59. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/format_common.py +0 -0
  60. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  61. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  62. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/parse_datasource.py +0 -0
  63. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/parse_pipe.py +0 -0
  64. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  65. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/pull.py +0 -0
  66. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/exceptions.py +0 -0
  67. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/feedback_manager.py +0 -0
  68. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/fmt.py +0 -0
  69. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/job.py +0 -0
  70. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/llm.py +0 -0
  71. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/local.py +0 -0
  72. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/local_common.py +0 -0
  73. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/login.py +0 -0
  74. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/regions.py +0 -0
  75. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/shell.py +0 -0
  76. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/table.py +0 -0
  77. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/tag.py +0 -0
  78. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/telemetry.py +0 -0
  79. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  80. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  81. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/token.py +0 -0
  82. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/workspace.py +0 -0
  83. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/workspace_members.py +0 -0
  84. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli.py +0 -0
  85. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/auth.py +0 -0
  86. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/branch.py +0 -0
  87. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/cicd.py +0 -0
  88. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/config.py +0 -0
  89. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/connection.py +0 -0
  90. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/datasource.py +0 -0
  91. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/exceptions.py +0 -0
  92. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/fmt.py +0 -0
  93. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/job.py +0 -0
  94. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/regions.py +0 -0
  95. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/tag.py +0 -0
  96. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/telemetry.py +0 -0
  97. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/test.py +0 -0
  98. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  99. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/workspace.py +0 -0
  100. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  101. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird.egg-info/dependency_links.txt +0 -0
  102. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird.egg-info/entry_points.txt +0 -0
  103. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird.egg-info/requires.txt +0 -0
  104. {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tinybird
3
- Version: 0.0.1.dev42
3
+ Version: 0.0.1.dev44
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -72,7 +72,7 @@ def parse_error_response(response: Response) -> str:
72
72
  if content.get("error", None):
73
73
  error = content["error"]
74
74
  if content.get("errors", None):
75
- error += f' -> errors: {content.get("errors")}'
75
+ error += f" -> errors: {content.get('errors')}"
76
76
  else:
77
77
  error = json.dumps(response, indent=4)
78
78
  return error
@@ -246,7 +246,7 @@ class BigQuery(Connector):
246
246
  uri='{self.gcs.gs_url()}{destination}*.csv',
247
247
  format='CSV',
248
248
  overwrite=true,
249
- header={ "true" if with_headers else "false" },
249
+ header={"true" if with_headers else "false"},
250
250
  field_delimiter=',') AS
251
251
  {sql}
252
252
  """
@@ -319,7 +319,7 @@ class Snowflake(Connector):
319
319
 
320
320
  def create_stage(self):
321
321
  sql = f"""
322
- create stage "{self.options['schema']}".{self.stage()}
322
+ create stage "{self.options["schema"]}".{self.stage()}
323
323
  url='{self.gcs.gcs_url()}'
324
324
  storage_integration = {self.storage_integration()};
325
325
  """
@@ -337,7 +337,7 @@ class Snowflake(Connector):
337
337
  from ({sql})
338
338
  overwrite = true
339
339
  file_format = (TYPE=CSV COMPRESSION=NONE ESCAPE_UNENCLOSED_FIELD=NONE FIELD_DELIMITER='|' FIELD_OPTIONALLY_ENCLOSED_BY='"' null_if=())
340
- header = {"true" if with_headers else "false" }
340
+ header = {"true" if with_headers else "false"}
341
341
  max_file_size = 2500000000;
342
342
  """
343
343
  self.execute(sql)
@@ -2175,8 +2175,8 @@ class PipeCheckerRunner:
2175
2175
  AND extractURLParameter(assumeNotNull(url), 'debug') <> 'query'
2176
2176
  AND error = 0
2177
2177
  AND not mapContains(parameters, '__tb__semver')
2178
- {" AND " + " AND ".join([f"mapContains(pipe_request_params, '{match}')" for match in matches]) if matches and len(matches) > 0 else ''}
2179
- { extra_where_clause }
2178
+ {" AND " + " AND ".join([f"mapContains(pipe_request_params, '{match}')" for match in matches]) if matches and len(matches) > 0 else ""}
2179
+ {extra_where_clause}
2180
2180
  Limit 5000000 -- Enough to bring data while not processing all requests from highly used pipes
2181
2181
  )
2182
2182
  group by request_param_names, http_method
@@ -2202,7 +2202,7 @@ class PipeCheckerRunner:
2202
2202
  AND extractURLParameter(assumeNotNull(url), 'debug') <> 'query'
2203
2203
  AND error = 0
2204
2204
  AND not mapContains(parameters, '__tb__semver')
2205
- {" AND " + " AND ".join([f"mapContains(pipe_request_params, '{match}')" for match in matches]) if matches and len(matches) > 0 else ''}
2205
+ {" AND " + " AND ".join([f"mapContains(pipe_request_params, '{match}')" for match in matches]) if matches and len(matches) > 0 else ""}
2206
2206
  {extra_where_clause}
2207
2207
  LIMIT {limit}
2208
2208
  )
@@ -4425,7 +4425,7 @@ async def folder_push(
4425
4425
  name=(
4426
4426
  name
4427
4427
  if to_run[name]["version"] is None
4428
- else f'{name}__v{to_run[name]["version"]}'
4428
+ else f"{name}__v{to_run[name]['version']}"
4429
4429
  )
4430
4430
  )
4431
4431
  )
@@ -4442,7 +4442,7 @@ async def folder_push(
4442
4442
  if raise_on_exists:
4443
4443
  raise AlreadyExistsException(
4444
4444
  FeedbackManager.warning_name_already_exists(
4445
- name=name if to_run[name]["version"] is None else f'{name}__v{to_run[name]["version"]}'
4445
+ name=name if to_run[name]["version"] is None else f"{name}__v{to_run[name]['version']}"
4446
4446
  )
4447
4447
  )
4448
4448
  else:
@@ -4457,7 +4457,7 @@ async def folder_push(
4457
4457
  name=(
4458
4458
  name
4459
4459
  if to_run[name]["version"] is None
4460
- else f'{name}__v{to_run[name]["version"]}'
4460
+ else f"{name}__v{to_run[name]['version']}"
4461
4461
  )
4462
4462
  )
4463
4463
  )
@@ -5013,7 +5013,7 @@ async def format_engine(
5013
5013
  else:
5014
5014
  if node.get("engine", None):
5015
5015
  empty = '""'
5016
- file_parts.append(f'ENGINE {node["engine"]["type"]}' if node.get("engine", {}).get("type") else empty)
5016
+ file_parts.append(f"ENGINE {node['engine']['type']}" if node.get("engine", {}).get("type") else empty)
5017
5017
  file_parts.append(DATAFILE_NEW_LINE)
5018
5018
  for arg in sorted(node["engine"].get("args", [])):
5019
5019
  elem = ", ".join([x.strip() for x in arg[1].split(",")])
@@ -5030,7 +5030,7 @@ async def format_node_type(file_parts: List[str], node: Dict[str, Any]) -> List[
5030
5030
  if node_type == PipeNodeTypes.MATERIALIZED:
5031
5031
  file_parts.append(node_type_upper)
5032
5032
  file_parts.append(DATAFILE_NEW_LINE)
5033
- file_parts.append(f'DATASOURCE {node["datasource"]}')
5033
+ file_parts.append(f"DATASOURCE {node['datasource']}")
5034
5034
  file_parts.append(DATAFILE_NEW_LINE)
5035
5035
  await format_engine(file_parts, node)
5036
5036
 
@@ -5038,10 +5038,10 @@ async def format_node_type(file_parts: List[str], node: Dict[str, Any]) -> List[
5038
5038
  if node_type == PipeNodeTypes.COPY:
5039
5039
  file_parts.append(node_type_upper)
5040
5040
  file_parts.append(DATAFILE_NEW_LINE)
5041
- file_parts.append(f'TARGET_DATASOURCE {node["target_datasource"]}')
5041
+ file_parts.append(f"TARGET_DATASOURCE {node['target_datasource']}")
5042
5042
  if node.get("mode"):
5043
5043
  file_parts.append(DATAFILE_NEW_LINE)
5044
- file_parts.append(f'COPY_MODE {node.get("mode")}')
5044
+ file_parts.append(f"COPY_MODE {node.get('mode')}")
5045
5045
 
5046
5046
  if node.get(CopyParameters.COPY_SCHEDULE):
5047
5047
  is_ondemand = node[CopyParameters.COPY_SCHEDULE].lower() == ON_DEMAND
@@ -5095,7 +5095,7 @@ async def format_node(
5095
5095
  if item and not unroll_includes:
5096
5096
  return
5097
5097
 
5098
- file_parts.append(f'NODE {node["name"].strip()}')
5098
+ file_parts.append(f"NODE {node['name'].strip()}")
5099
5099
  file_parts.append(DATAFILE_NEW_LINE)
5100
5100
 
5101
5101
  from collections import namedtuple
@@ -951,7 +951,7 @@ Ready? """
951
951
  )
952
952
  success_datasource_alter = success_message("** The Data Source has been correctly updated.")
953
953
  success_datasource_kafka_connected = success_message(
954
- "** Data Source '{id}' created\n" "** Kafka streaming connection configured successfully!"
954
+ "** Data Source '{id}' created\n** Kafka streaming connection configured successfully!"
955
955
  )
956
956
  success_datasource_shared = success_message(
957
957
  "** The Data Source {datasource} has been correctly shared with {workspace}"
@@ -373,6 +373,7 @@ You are a Tinybird expert. You will be given a pipe containing different nodes w
373
373
  - The parameter within Tinybird templating syntax looks like this one {{String(my_param_name, default_value)}}.
374
374
  - If there are no parameters, you can omit parameters and generate a single test.
375
375
  - The format of the parameters is the following: ?param1=value1&param2=value2&param3=value3
376
+ - 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.
376
377
  </instructions>
377
378
 
378
379
  This is an example of a test with parameters:
@@ -396,9 +397,19 @@ Follow the instructions and generate the following response with no additional t
396
397
  """
397
398
 
398
399
 
399
- def create_prompt(existing_resources: str) -> str:
400
+ def create_prompt(existing_resources: str, feedback: str = "", history: str = "") -> str:
401
+ feedback_history = ""
402
+ if feedback and history:
403
+ feedback_history = f"""In case the <feedback> and <history> tags are present and not empty,
404
+ it means there was a previous attempt to generate the resources and the user provided feedback and history about previous responses.
405
+ Use the following feedback and history to regenerate the response:
406
+ Feedback to improve the response:
407
+ {feedback}
408
+ History of previous results:
409
+ {history}"""
410
+
400
411
  return """
401
- You are a Tinybird expert. You will be given a prompt to generate Tinybird resources: datasources and/or pipes.
412
+ You are a Tinybird expert. You will be given a prompt to generate new or update existing Tinybird resources: datasources and/or pipes.
402
413
  <existing_resources>{existing_resources}</existing_resources>
403
414
  {datasource_instructions}
404
415
  {pipe_instructions}
@@ -407,6 +418,9 @@ You are a Tinybird expert. You will be given a prompt to generate Tinybird resou
407
418
  {pipe_example}
408
419
  {copy_pipe_instructions}
409
420
  {materialized_pipe_instructions}
421
+
422
+ {feedback_history}
423
+
410
424
  Use the following format to generate the response and do not wrap it in any other text, including the <response> tag.
411
425
  <response>
412
426
  <resource>
@@ -425,10 +439,21 @@ Use the following format to generate the response and do not wrap it in any othe
425
439
  pipe_example=pipe_example,
426
440
  copy_pipe_instructions=copy_pipe_instructions,
427
441
  materialized_pipe_instructions=materialized_pipe_instructions,
442
+ feedback_history=feedback_history,
428
443
  )
429
444
 
430
445
 
431
- def mock_prompt(rows: int) -> str:
446
+ def mock_prompt(rows: int, feedback: str = "", history: str = "") -> str:
447
+ feedback_history = ""
448
+ if feedback and history:
449
+ feedback_history = f"""In case the <feedback> and <history> tags are present and not empty,
450
+ it means there was a previous attempt to generate the resources and the user provided feedback and history about previous responses.
451
+ Use the following feedback and history to regenerate the response:
452
+ Feedback to improve the response:
453
+ {feedback}
454
+ History of previous results:
455
+ {history}"""
456
+
432
457
  return f"""
433
458
  Given the schema for a Tinybird datasource, return a can you create a clickhouse sql query to generate some random data that matches that schema.
434
459
 
@@ -569,6 +594,9 @@ Follow the instructions and generate the following response with no additional t
569
594
  <response>
570
595
  <sql>[raw sql query here]</sql>
571
596
  </response>
597
+
598
+ {feedback_history}
599
+
572
600
  """
573
601
 
574
602
 
@@ -241,7 +241,7 @@ def format_parse_error(
241
241
  message += f" found at position {adjusted_position - len(keyword)}"
242
242
  else:
243
243
  message += (
244
- f" found {repr(table_structure[i]) if len(table_structure)>i else 'EOF'} at position {adjusted_position}"
244
+ f" found {repr(table_structure[i]) if len(table_structure) > i else 'EOF'} at position {adjusted_position}"
245
245
  )
246
246
  return message
247
247
 
@@ -100,7 +100,7 @@ def _format_jinja_node(self, node: Node, max_length: int) -> bool:
100
100
  parts = tag.code.split("\n")
101
101
  prefix = INDENT * (node.depth[0] + node.depth[1])
102
102
  if len(parts) > 1:
103
- tag.code = "\n".join([f'{prefix if i != 0 else ""}{part}' for i, part in enumerate(parts)])
103
+ tag.code = "\n".join([f"{prefix if i != 0 else ''}{part}" for i, part in enumerate(parts)])
104
104
 
105
105
  node.value = str(tag)
106
106
 
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
4
4
  __url__ = 'https://www.tinybird.co/docs/cli/introduction.html'
5
5
  __author__ = 'Tinybird'
6
6
  __author_email__ = 'support@tinybird.co'
7
- __version__ = '0.0.1.dev42'
8
- __revision__ = '14b255c'
7
+ __version__ = '0.0.1.dev44'
8
+ __revision__ = '637cb4c'
@@ -6,7 +6,6 @@ if sys.platform == "win32":
6
6
 
7
7
  import tinybird.tb.modules.auth
8
8
  import tinybird.tb.modules.build
9
- import tinybird.tb.modules.build_client
10
9
  import tinybird.tb.modules.cli
11
10
  import tinybird.tb.modules.common
12
11
  import tinybird.tb.modules.copy
@@ -18,6 +17,7 @@ import tinybird.tb.modules.fmt
18
17
  import tinybird.tb.modules.job
19
18
  import tinybird.tb.modules.local
20
19
  import tinybird.tb.modules.login
20
+ import tinybird.tb.modules.materialization
21
21
  import tinybird.tb.modules.mock
22
22
  import tinybird.tb.modules.pipe
23
23
  import tinybird.tb.modules.tag
@@ -12,6 +12,7 @@ import requests
12
12
  from tinybird.client import TinyB
13
13
  from tinybird.tb.modules.cli import cli
14
14
  from tinybird.tb.modules.common import push_data
15
+ from tinybird.tb.modules.datafile.build import folder_build
15
16
  from tinybird.tb.modules.datafile.fixture import build_fixture_name, get_fixture_dir
16
17
  from tinybird.tb.modules.feedback_manager import FeedbackManager
17
18
  from tinybird.tb.modules.local_common import get_tinybird_local_client
@@ -31,17 +32,17 @@ def build(ctx: click.Context, watch: bool) -> None:
31
32
  project: Project = ctx.ensure_object(dict)["project"]
32
33
  tb_client = asyncio.run(get_tinybird_local_client(str(project.path)))
33
34
  click.echo(FeedbackManager.highlight(message="\n» Building project..."))
34
-
35
35
  time_start = time.time()
36
36
 
37
- def process(file_changed: Optional[str] = None) -> None:
37
+ def process(file_changed: Optional[str] = None, diff: Optional[str] = None) -> None:
38
38
  if file_changed and file_changed.endswith(".ndjson"):
39
39
  rebuild_fixture(project, tb_client, file_changed)
40
40
  else:
41
- build_project(project, tb_client)
41
+ build_project(project, tb_client, file_changed)
42
42
  try:
43
43
  if file_changed:
44
- build_and_print_resource(tb_client, file_changed)
44
+ asyncio.run(folder_build(project, filenames=[file_changed]))
45
+ build_and_print_resource(tb_client, file_changed, diff)
45
46
  except Exception:
46
47
  pass
47
48
 
@@ -62,7 +63,7 @@ def build(ctx: click.Context, watch: bool) -> None:
62
63
  shell.run()
63
64
 
64
65
 
65
- def build_project(project: Project, tb_client: TinyB) -> None:
66
+ def build_project(project: Project, tb_client: TinyB, file_changed: Optional[str] = None) -> None:
66
67
  MULTIPART_BOUNDARY_DATA_PROJECT = "data_project://"
67
68
  DATAFILE_TYPE_TO_CONTENT_TYPE = {
68
69
  ".datasource": "text/plain",
@@ -79,6 +80,9 @@ def build_project(project: Project, tb_client: TinyB) -> None:
79
80
  project_path = project.path
80
81
  project_files = project.get_project_files()
81
82
 
83
+ if not project_files:
84
+ return
85
+
82
86
  for file_path in project_files:
83
87
  relative_path = str(Path(file_path).relative_to(project_path))
84
88
  fd = open(file_path, "rb")
@@ -101,17 +105,23 @@ def build_project(project: Project, tb_client: TinyB) -> None:
101
105
  if build_result == "success":
102
106
  datasources = result.get("datasources", [])
103
107
  pipes = result.get("pipes", [])
104
- for ds in datasources:
105
- ds_path = next((p for p in project_files if p.endswith(ds.get("name") + ".datasource")), None)
106
- if ds_path:
107
- ds_path = ds_path.replace(f"{project.folder}/", "")
108
- click.echo(FeedbackManager.info(message=f"✓ {ds_path} created"))
109
- for pipe in pipes:
110
- pipe_name = pipe.get("name")
111
- pipe_path = next((p for p in project_files if p.endswith(pipe_name + ".pipe")), None)
112
- if pipe_path:
113
- pipe_path = pipe_path.replace(f"{project.folder}/", "")
114
- click.echo(FeedbackManager.info(message=f"✓ {pipe_path} created"))
108
+ if not file_changed:
109
+ for ds in datasources:
110
+ ds_path_str: Optional[str] = next(
111
+ (p for p in project_files if p.endswith(ds.get("name") + ".datasource")), None
112
+ )
113
+ if ds_path_str:
114
+ ds_path = Path(ds_path_str)
115
+ ds_path_str = ds_path_str.replace(f"{project.folder}/", "")
116
+ click.echo(FeedbackManager.info(message=f"✓ {ds_path_str} created"))
117
+ for pipe in pipes:
118
+ pipe_name = pipe.get("name")
119
+ pipe_path_str: Optional[str] = next(
120
+ (p for p in project_files if p.endswith(pipe_name + ".pipe")), None
121
+ )
122
+ if pipe_path_str:
123
+ pipe_path_str = pipe_path_str.replace(f"{project.folder}/", "")
124
+ click.echo(FeedbackManager.info(message=f"✓ {pipe_path_str} created"))
115
125
 
116
126
  try:
117
127
  for filename in project_files:
@@ -185,9 +195,17 @@ def rebuild_fixture(project: Project, tb_client: TinyB, fixture: str) -> None:
185
195
  click.echo(FeedbackManager.error_exception(error=e))
186
196
 
187
197
 
188
- def build_and_print_resource(tb_client: TinyB, filename: str):
198
+ def build_and_print_resource(tb_client: TinyB, filename: str, diff: Optional[str] = None):
199
+ table_name = diff
189
200
  resource_path = Path(filename)
190
- name = resource_path.stem
191
- pipeline = name if filename.endswith(".pipe") else None
192
- res = asyncio.run(tb_client.query(f"SELECT * FROM {name} FORMAT JSON", pipeline=pipeline))
193
- print_table_formatted(res, name)
201
+ resource_name = resource_path.stem
202
+
203
+ pipeline = resource_name if filename.endswith(".pipe") else None
204
+
205
+ if not table_name:
206
+ table_name = resource_name
207
+
208
+ sql = f"SELECT * FROM {table_name} FORMAT JSON"
209
+
210
+ res = asyncio.run(tb_client.query(sql, pipeline=pipeline))
211
+ print_table_formatted(res, table_name)
@@ -39,7 +39,7 @@ jobs:
39
39
  working-directory: '{{ data_project_dir }}'
40
40
  services:
41
41
  tinybird:
42
- image: tinybirdco/tinybird-local:latest
42
+ image: tinybirdco/tinybird-local:beta
43
43
  ports:
44
44
  - 80:80
45
45
  steps:
@@ -83,7 +83,7 @@ tinybird_ci_workflow:
83
83
  - tb build
84
84
  - tb test run
85
85
  services:
86
- - name: tinybirdco/tinybird-local:latest
86
+ - name: tinybirdco/tinybird-local:beta
87
87
  alias: tinybird-local
88
88
  """
89
89
 
@@ -6,10 +6,9 @@
6
6
  import json
7
7
  import logging
8
8
  import os
9
- import pprint
10
9
  from os import getcwd
11
10
  from pathlib import Path
12
- from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union
11
+ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
13
12
 
14
13
  import click
15
14
  import humanfriendly
@@ -35,13 +34,7 @@ from tinybird.tb.modules.common import (
35
34
  )
36
35
  from tinybird.tb.modules.config import CLIConfig
37
36
  from tinybird.tb.modules.datafile.build import build_graph
38
- from tinybird.tb.modules.datafile.common import Datafile, DatafileSyntaxError
39
37
  from tinybird.tb.modules.datafile.diff import diff_command
40
- from tinybird.tb.modules.datafile.exceptions import (
41
- ParseException,
42
- )
43
- from tinybird.tb.modules.datafile.parse_datasource import parse_datasource
44
- from tinybird.tb.modules.datafile.parse_pipe import parse_pipe
45
38
  from tinybird.tb.modules.datafile.pull import folder_pull
46
39
  from tinybird.tb.modules.feedback_manager import FeedbackManager
47
40
  from tinybird.tb.modules.llm import LLM
@@ -66,15 +59,17 @@ VERSION = f"{__cli__.__version__} (rev {__cli__.__revision__})"
66
59
  @click.option("--host", help="Use custom host, defaults to TB_HOST envvar, then to https://api.tinybird.co")
67
60
  @click.option("--show-tokens", is_flag=True, default=False, help="Enable the output of tokens")
68
61
  @click.option("--prod/--local", is_flag=True, default=False, help="Run against production or local")
69
- @click.option("--folder", type=str, default=os.getcwd(), help="Folder where files will be placed")
62
+ @click.option("--folder", type=str, help="Folder where files will be placed")
70
63
  @click.version_option(version=VERSION)
71
64
  @click.pass_context
72
65
  @coro
73
- async def cli(ctx: Context, debug: bool, token: str, host: str, show_tokens: bool, prod: bool, folder: str) -> None:
66
+ async def cli(
67
+ ctx: Context, debug: bool, token: str, host: str, show_tokens: bool, prod: bool, folder: Optional[str]
68
+ ) -> None:
74
69
  """
75
70
  Use `OBFUSCATE_REGEX_PATTERN` and `OBFUSCATE_PATTERN_SEPARATOR` environment variables to define a regex pattern and a separator (in case of a single string with multiple regex) to obfuscate secrets in the CLI output.
76
71
  """
77
- project = Project(folder=folder)
72
+ project = Project(folder=folder or os.getcwd())
78
73
  # We need to unpatch for our tests not to break
79
74
  if show_tokens or not prod or ctx.invoked_subcommand == "build":
80
75
  __unpatch_click_output()
@@ -87,7 +82,7 @@ async def cli(ctx: Context, debug: bool, token: str, host: str, show_tokens: boo
87
82
  if debug:
88
83
  logging.basicConfig(level=logging.DEBUG)
89
84
 
90
- config_temp = CLIConfig.get_project_config(project.path)
85
+ config_temp = CLIConfig.get_project_config(str(project.path))
91
86
  if token:
92
87
  config_temp.set_token(token)
93
88
  if host:
@@ -130,55 +125,7 @@ async def cli(ctx: Context, debug: bool, token: str, host: str, show_tokens: boo
130
125
  ctx.ensure_object(dict)["project"] = project
131
126
 
132
127
 
133
- @cli.command(hidden=True)
134
- @click.argument("filenames", type=click.Path(exists=True), nargs=-1, default=None)
135
- @click.option("--debug", is_flag=True, default=False, help="Print internal representation")
136
- @click.pass_context
137
- def check(ctx: Context, filenames: List[str], debug: bool) -> None:
138
- """Check file syntax."""
139
-
140
- if not filenames:
141
- project: Project = ctx.ensure_object(dict)["project"]
142
- filenames = project.get_project_files()
143
-
144
- def process(filenames: Iterable):
145
- parser_matrix = {".pipe": parse_pipe, ".datasource": parse_datasource}
146
- incl_suffix = ".incl"
147
- try:
148
- for filename in filenames:
149
- if os.path.isdir(filename):
150
- process(filenames=filename)
151
-
152
- click.echo(FeedbackManager.info_processing_file(filename=filename))
153
-
154
- file_suffix = Path(filename).suffix
155
- if file_suffix == incl_suffix:
156
- click.echo(FeedbackManager.info_ignoring_incl_file(filename=filename))
157
- continue
158
-
159
- doc: Datafile
160
- parser = parser_matrix.get(file_suffix)
161
- if not parser:
162
- raise ParseException(FeedbackManager.error_unsupported_datafile(extension=file_suffix))
163
-
164
- doc = parser(filename)
165
-
166
- click.echo(FeedbackManager.success_processing_file(filename=filename))
167
- if debug:
168
- pp = pprint.PrettyPrinter()
169
- for x in doc.nodes:
170
- pp.pprint(x)
171
-
172
- except DatafileSyntaxError as e:
173
- # TODO(eclbg): add the filename to the error message
174
- raise CLIException(str(e))
175
- except ParseException as e:
176
- raise CLIException(FeedbackManager.error_exception(error=e))
177
-
178
- process(filenames=filenames)
179
-
180
-
181
- @cli.command(hidden=True)
128
+ @cli.command()
182
129
  @click.option(
183
130
  "--folder", default=None, type=click.Path(exists=True, file_okay=False), help="Folder where files will be placed"
184
131
  )
@@ -163,7 +163,7 @@ def generate_datafile(
163
163
  force: Optional[bool] = False,
164
164
  _format: Optional[str] = "csv",
165
165
  folder: Optional[str] = None,
166
- ):
166
+ ) -> Path:
167
167
  p = Path(filename)
168
168
  base = Path("datasources")
169
169
  if folder:
@@ -190,6 +190,7 @@ def generate_datafile(
190
190
  fixture_file.write(data[: data.rfind(newline)])
191
191
  else:
192
192
  click.echo(FeedbackManager.error_file_already_exists(file=f))
193
+ return f
193
194
 
194
195
 
195
196
  async def get_current_workspace(config: CLIConfig) -> Optional[Dict[str, Any]]: