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.
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/PKG-INFO +1 -1
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/client.py +1 -1
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/connectors.py +3 -3
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/datafile.py +11 -11
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/feedback_manager.py +1 -1
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/prompts.py +31 -3
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/sql.py +1 -1
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/sql_template_fmt.py +1 -1
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/__cli__.py +2 -2
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/cli.py +1 -1
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/build.py +39 -21
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/cicd.py +2 -2
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/cli.py +8 -61
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/common.py +2 -1
- tinybird-0.0.1.dev44/tinybird/tb/modules/copy.py +159 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/create.py +105 -46
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/build.py +64 -247
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datasource.py +1 -1
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/deployment.py +86 -61
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/endpoint.py +90 -3
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/llm_utils.py +2 -2
- tinybird-0.0.1.dev44/tinybird/tb/modules/materialization.py +146 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/mock.py +56 -16
- tinybird-0.0.1.dev42/tinybird/tb/modules/copy.py → tinybird-0.0.1.dev44/tinybird/tb/modules/pipe.py +14 -11
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/project.py +31 -1
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/test.py +72 -37
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/update.py +1 -1
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/watch.py +54 -5
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/cli.py +1 -1
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/common.py +1 -1
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/pipe.py +1 -1
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +1 -1
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tornado_template.py +2 -2
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird.egg-info/PKG-INFO +1 -1
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird.egg-info/SOURCES.txt +1 -1
- tinybird-0.0.1.dev42/tinybird/tb/modules/build_client.py +0 -199
- tinybird-0.0.1.dev42/tinybird/tb/modules/pipe.py +0 -480
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/setup.cfg +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/__cli__.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/ch_utils/constants.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/ch_utils/engine.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/check_pypi.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/config.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/context.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/datatypes.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/git_settings.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/sql_template.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/sql_toolset.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/syncasync.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/auth.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/config.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/build_common.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/common.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/diff.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/exceptions.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/fixture.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/format_common.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/parse_datasource.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/parse_pipe.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/datafile/pull.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/exceptions.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/feedback_manager.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/fmt.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/job.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/llm.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/local.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/local_common.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/login.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/regions.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/shell.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/table.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/tag.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/telemetry.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/token.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/workspace.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb/modules/workspace_members.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/auth.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/branch.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/cicd.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/config.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/connection.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/datasource.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/exceptions.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/fmt.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/job.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/regions.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/tag.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/telemetry.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/test.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/workspace.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird/tb_cli_modules/workspace_members.py +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird.egg-info/dependency_links.txt +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird.egg-info/entry_points.txt +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird.egg-info/requires.txt +0 -0
- {tinybird-0.0.1.dev42 → tinybird-0.0.1.dev44}/tinybird.egg-info/top_level.txt +0 -0
|
@@ -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
|
|
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={
|
|
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[
|
|
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
|
-
{
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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¶m2=value2¶m3=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
|
|
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.
|
|
8
|
-
__revision__ = '
|
|
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
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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:
|
|
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:
|
|
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,
|
|
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,
|
|
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(
|
|
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(
|
|
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]]:
|