tinybird 0.0.1.dev35__tar.gz → 0.0.1.dev36__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 (102) hide show
  1. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/PKG-INFO +1 -1
  2. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/prompts.py +2 -0
  3. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/__cli__.py +2 -2
  4. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/build.py +33 -12
  5. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/cli.py +7 -94
  6. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/create.py +4 -4
  7. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datafile/build.py +2 -2
  8. tinybird-0.0.1.dev36/tinybird/tb/modules/llm.py +32 -0
  9. tinybird-0.0.1.dev36/tinybird/tb/modules/llm_utils.py +111 -0
  10. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/local_common.py +2 -2
  11. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/mock.py +3 -4
  12. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/test.py +2 -2
  13. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/update.py +4 -4
  14. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird.egg-info/PKG-INFO +1 -1
  15. tinybird-0.0.1.dev35/tinybird/tb/modules/llm.py +0 -38
  16. tinybird-0.0.1.dev35/tinybird/tb/modules/llm_utils.py +0 -24
  17. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/setup.cfg +0 -0
  18. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/__cli__.py +0 -0
  19. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/ch_utils/constants.py +0 -0
  20. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/ch_utils/engine.py +0 -0
  21. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/check_pypi.py +0 -0
  22. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/client.py +0 -0
  23. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/config.py +0 -0
  24. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/connectors.py +0 -0
  25. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/context.py +0 -0
  26. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/datafile.py +0 -0
  27. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/datatypes.py +0 -0
  28. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/feedback_manager.py +0 -0
  29. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/git_settings.py +0 -0
  30. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/sql.py +0 -0
  31. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/sql_template.py +0 -0
  32. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/sql_template_fmt.py +0 -0
  33. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/sql_toolset.py +0 -0
  34. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/syncasync.py +0 -0
  35. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/cli.py +0 -0
  36. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/auth.py +0 -0
  37. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/build_client.py +0 -0
  38. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/cicd.py +0 -0
  39. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/common.py +0 -0
  40. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/config.py +0 -0
  41. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datafile/build_common.py +0 -0
  42. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  43. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  44. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datafile/common.py +0 -0
  45. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datafile/diff.py +0 -0
  46. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datafile/exceptions.py +0 -0
  47. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datafile/fixture.py +0 -0
  48. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datafile/format_common.py +0 -0
  49. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  50. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  51. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datafile/parse_datasource.py +0 -0
  52. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datafile/parse_pipe.py +0 -0
  53. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  54. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datafile/pull.py +0 -0
  55. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/datasource.py +0 -0
  56. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/deployment.py +0 -0
  57. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/endpoint.py +0 -0
  58. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/exceptions.py +0 -0
  59. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/feedback_manager.py +0 -0
  60. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/fmt.py +0 -0
  61. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/job.py +0 -0
  62. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/local.py +0 -0
  63. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/login.py +0 -0
  64. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/pipe.py +0 -0
  65. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/regions.py +0 -0
  66. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/shell.py +0 -0
  67. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/table.py +0 -0
  68. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/tag.py +0 -0
  69. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/telemetry.py +0 -0
  70. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  71. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  72. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/token.py +0 -0
  73. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/watch.py +0 -0
  74. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/workspace.py +0 -0
  75. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb/modules/workspace_members.py +0 -0
  76. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli.py +0 -0
  77. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/auth.py +0 -0
  78. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/branch.py +0 -0
  79. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/cicd.py +0 -0
  80. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/cli.py +0 -0
  81. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/common.py +0 -0
  82. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/config.py +0 -0
  83. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/connection.py +0 -0
  84. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/datasource.py +0 -0
  85. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/exceptions.py +0 -0
  86. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/fmt.py +0 -0
  87. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/job.py +0 -0
  88. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/pipe.py +0 -0
  89. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/regions.py +0 -0
  90. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/tag.py +0 -0
  91. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/telemetry.py +0 -0
  92. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/test.py +0 -0
  93. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  94. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  95. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/workspace.py +0 -0
  96. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  97. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird/tornado_template.py +0 -0
  98. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird.egg-info/SOURCES.txt +0 -0
  99. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird.egg-info/dependency_links.txt +0 -0
  100. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird.egg-info/entry_points.txt +0 -0
  101. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/tinybird.egg-info/requires.txt +0 -0
  102. {tinybird-0.0.1.dev35 → tinybird-0.0.1.dev36}/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.dev35
3
+ Version: 0.0.1.dev36
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -641,6 +641,7 @@ The previous instructions are explanations of how things work in Tinybird. Answe
641
641
 
642
642
  datasource_instructions = """
643
643
  <datasource_file_instructions>
644
+ - Content cannot be empty.
644
645
  - The datasource names must be unique.
645
646
  - No indentation is allowed for property names: DESCRIPTION, SCHEMA, ENGINE, ENGINE_PARTITION_KEY, ENGINE_SORTING_KEY, etc.
646
647
  - Use MergeTree engine by default.
@@ -701,6 +702,7 @@ sql_instructions = """
701
702
  </valid_query_with_parameters_with_%_on_top>
702
703
  - The Parameter functions like this one {{{{String(my_param_name,default_value)}}}} can be one of the following: String, DateTime, Date, Float32, Float64, Int, Integer, UInt8, UInt16, UInt32, UInt64, UInt128, UInt256, Int8, Int16, Int32, Int64, Int128, Int256
703
704
  - Parameter names must be different from column names. Pass always the param name and a default value to the function.
705
+ - Use ALWAYS hardcoded values for default values for parameters.
704
706
  - Code inside the template {{{{template_expression}}}} follows the rules of Tornado templating language so no module is allowed to be imported. So for example you can't use now() as default value for a DateTime parameter. You need an if else block like this:
705
707
  <invalid_condition_with_now>
706
708
  AND timestamp BETWEEN {{DateTime(start_date, now() - interval 30 day)}} AND {{DateTime(end_date, now())}}
@@ -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.dev35'
8
- __revision__ = '5046116'
7
+ __version__ = '0.0.1.dev36'
8
+ __revision__ = '5ad3ab4'
@@ -2,6 +2,7 @@ import asyncio
2
2
  import glob
3
3
  import json
4
4
  import logging
5
+ import os
5
6
  import threading
6
7
  import time
7
8
  from pathlib import Path
@@ -13,6 +14,7 @@ import requests
13
14
  from tinybird.client import TinyB
14
15
  from tinybird.tb.modules.cli import cli
15
16
  from tinybird.tb.modules.common import push_data
17
+ from tinybird.tb.modules.datafile.fixture import build_fixture_name, get_fixture_dir
16
18
  from tinybird.tb.modules.feedback_manager import FeedbackManager
17
19
  from tinybird.tb.modules.local_common import get_tinybird_local_client
18
20
  from tinybird.tb.modules.shell import Shell
@@ -20,7 +22,7 @@ from tinybird.tb.modules.watch import watch_project
20
22
 
21
23
 
22
24
  @cli.command()
23
- @click.option("--folder", type=str, default=".")
25
+ @click.option("--folder", type=str, default=os.getcwd())
24
26
  @click.option("--watch", is_flag=True, default=False, help="Watch for changes and rebuild automatically")
25
27
  def build(folder: str, watch: bool) -> None:
26
28
  """
@@ -30,11 +32,13 @@ def build(folder: str, watch: bool) -> None:
30
32
  tb_client = asyncio.run(get_tinybird_local_client(folder))
31
33
  click.echo(FeedbackManager.highlight(message="\n» Building project..."))
32
34
 
35
+ time_start = time.time()
36
+
33
37
  def process() -> None:
34
38
  build_project(folder, tb_client)
35
39
 
36
- time_start = time.time()
37
40
  process()
41
+
38
42
  time_end = time.time()
39
43
  elapsed_time = time_end - time_start
40
44
  click.echo(FeedbackManager.success(message=f"\n✓ Build completed in {elapsed_time:.1f}s"))
@@ -112,6 +116,20 @@ def build_project(folder: str, tb_client: TinyB) -> None:
112
116
  pipe_path = pipe_path.replace(f"{folder}/", "")
113
117
  click.echo(FeedbackManager.info(message=f"✓ {pipe_path} created"))
114
118
 
119
+ for filename in project_files:
120
+ if filename.endswith(".datasource"):
121
+ ds_path = Path(filename)
122
+ ds_name = ds_path.stem
123
+ name = build_fixture_name(filename, ds_name, ds_path.read_text())
124
+ fixture_folder = get_fixture_dir(folder)
125
+ fixture_path = fixture_folder / f"{name}.ndjson"
126
+
127
+ if not fixture_path.exists():
128
+ fixture_path = fixture_folder / f"{ds_name}.ndjson"
129
+
130
+ if fixture_path.exists():
131
+ append_fixture(tb_client, ds_name, str(fixture_path))
132
+
115
133
  elif build_result == "failed":
116
134
  click.echo(FeedbackManager.error(message="Build failed"))
117
135
  build_errors = result.get("errors")
@@ -121,24 +139,27 @@ def build_project(folder: str, tb_client: TinyB) -> None:
121
139
  click.echo(FeedbackManager.error(message=error_msg))
122
140
  else:
123
141
  click.echo(FeedbackManager.error(message=f"Unknown build result. Error: {result.get('error')}"))
142
+
124
143
  except Exception as e:
125
- click.echo(FeedbackManager.error_exception(error="Error building project: " + str(e)))
144
+ click.echo(FeedbackManager.error_exception(error="Error: " + str(e)))
126
145
  finally:
127
146
  for fd in fds:
128
147
  fd.close()
129
148
 
130
149
 
131
- async def append_fixture(
150
+ def append_fixture(
132
151
  tb_client: TinyB,
133
152
  datasource_name: str,
134
153
  url: str,
135
154
  ):
136
- await tb_client.datasource_truncate(datasource_name)
137
- await push_data(
138
- tb_client,
139
- datasource_name,
140
- url,
141
- mode="append",
142
- concurrency=1,
143
- silent=True,
155
+ asyncio.run(tb_client.datasource_truncate(datasource_name))
156
+ asyncio.run(
157
+ push_data(
158
+ tb_client,
159
+ datasource_name,
160
+ url,
161
+ mode="append",
162
+ concurrency=1,
163
+ silent=True,
164
+ )
144
165
  )
@@ -67,58 +67,13 @@ VERSION = f"{__cli__.__version__} (rev {__cli__.__revision__})"
67
67
  )
68
68
  @click.option("--token", help="Use auth token, defaults to TB_TOKEN envvar, then to the .tinyb file")
69
69
  @click.option("--host", help="Use custom host, defaults to TB_HOST envvar, then to https://api.tinybird.co")
70
- @click.option("--gcp-project-id", help="The Google Cloud project ID", hidden=True)
71
- @click.option(
72
- "--gcs-bucket", help="The Google Cloud Storage bucket to write temp files when using the connectors", hidden=True
73
- )
74
- @click.option(
75
- "--google-application-credentials",
76
- envvar="GOOGLE_APPLICATION_CREDENTIALS",
77
- help="Set GOOGLE_APPLICATION_CREDENTIALS",
78
- hidden=True,
79
- )
80
- @click.option("--sf-account", help="The Snowflake Account (e.g. your-domain.west-europe.azure)", hidden=True)
81
- @click.option("--sf-warehouse", help="The Snowflake warehouse name", hidden=True)
82
- @click.option("--sf-database", help="The Snowflake database name", hidden=True)
83
- @click.option("--sf-schema", help="The Snowflake schema name", hidden=True)
84
- @click.option("--sf-role", help="The Snowflake role name", hidden=True)
85
- @click.option("--sf-user", help="The Snowflake user name", hidden=True)
86
- @click.option("--sf-password", help="The Snowflake password", hidden=True)
87
- @click.option(
88
- "--sf-storage-integration",
89
- help="The Snowflake GCS storage integration name (leave empty to auto-generate one)",
90
- hidden=True,
91
- )
92
- @click.option("--sf-stage", help="The Snowflake GCS stage name (leave empty to auto-generate one)", hidden=True)
93
- @click.option(
94
- "--with-headers", help="Flag to enable connector to export with headers", is_flag=True, default=False, hidden=True
95
- )
96
70
  @click.option("--show-tokens", is_flag=True, default=False, help="Enable the output of tokens")
97
- @click.option("--prod/--local", is_flag=True, default=False, help="Run against production or local")
71
+ @click.option("--show-tokens", is_flag=True, default=False, help="Enable the output of tokens")
72
+ @click.option("--prod", is_flag=True, default=False, help="Run against production")
98
73
  @click.version_option(version=VERSION)
99
74
  @click.pass_context
100
75
  @coro
101
- async def cli(
102
- ctx: Context,
103
- debug: bool,
104
- token: str,
105
- host: str,
106
- gcp_project_id: str,
107
- gcs_bucket: str,
108
- google_application_credentials: str,
109
- sf_account: str,
110
- sf_warehouse: str,
111
- sf_database: str,
112
- sf_schema: str,
113
- sf_role: str,
114
- sf_user: str,
115
- sf_password: str,
116
- sf_storage_integration: str,
117
- sf_stage,
118
- with_headers: bool,
119
- show_tokens: bool,
120
- prod: bool,
121
- ) -> None:
76
+ async def cli(ctx: Context, debug: bool, token: str, host: str, show_tokens: bool, prod: bool) -> None:
122
77
  """
123
78
  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.
124
79
  """
@@ -166,51 +121,9 @@ async def cli(
166
121
 
167
122
  ctx.ensure_object(dict)["config"] = config
168
123
 
169
- if ctx.invoked_subcommand == "auth":
170
- return
171
-
172
- from tinybird.connectors import create_connector
173
-
174
- if gcp_project_id and gcs_bucket and google_application_credentials and not sf_account:
175
- bq_config = {
176
- "project_id": gcp_project_id,
177
- "bucket_name": gcs_bucket,
178
- "service_account": google_application_credentials,
179
- "with_headers": with_headers,
180
- }
181
- ctx.ensure_object(dict)["bigquery"] = create_connector("bigquery", bq_config)
182
- if (
183
- sf_account
184
- and sf_warehouse
185
- and sf_database
186
- and sf_schema
187
- and sf_role
188
- and sf_user
189
- and sf_password
190
- and gcs_bucket
191
- and google_application_credentials
192
- and gcp_project_id
193
- ):
194
- sf_config = {
195
- "account": sf_account,
196
- "warehouse": sf_warehouse,
197
- "database": sf_database,
198
- "schema": sf_schema,
199
- "role": sf_role,
200
- "user": sf_user,
201
- "password": sf_password,
202
- "storage_integration": sf_storage_integration,
203
- "stage": sf_stage,
204
- "bucket_name": gcs_bucket,
205
- "service_account": google_application_credentials,
206
- "project_id": gcp_project_id,
207
- "with_headers": with_headers,
208
- }
209
- ctx.ensure_object(dict)["snowflake"] = create_connector("snowflake", sf_config)
210
-
211
124
  logging.debug("debug enabled")
212
125
 
213
- skip_client = ctx.invoked_subcommand in ["login", "workspace", "local", "build"]
126
+ skip_client = ctx.invoked_subcommand in ["auth", "login", "workspace", "local", "build"]
214
127
  client = await create_ctx_client(config, prod, skip_client)
215
128
 
216
129
  if client:
@@ -487,7 +400,7 @@ async def sql(
487
400
 
488
401
  @cli.command(hidden=True)
489
402
  @click.argument("prompt")
490
- @click.option("--folder", default=".", help="The folder to use for the project")
403
+ @click.option("--folder", default=os.getcwd(), help="The folder to use for the project")
491
404
  @coro
492
405
  async def ask(prompt: str, folder: str) -> None:
493
406
  """Ask things about your data project."""
@@ -529,8 +442,8 @@ async def ask(prompt: str, folder: str) -> None:
529
442
  )
530
443
 
531
444
  client = config.get_client()
532
- llm = LLM(user_token=user_token, client=client)
533
- click.echo(await llm.ask(system_prompt=ask_prompt(resources_xml), prompt=prompt))
445
+ llm = LLM(user_token=user_token, host=client.host)
446
+ click.echo(llm.ask(system_prompt=ask_prompt(resources_xml), prompt=prompt))
534
447
  except Exception as e:
535
448
  raise CLIException(FeedbackManager.error_exception(error=e))
536
449
 
@@ -103,13 +103,13 @@ async def create(
103
103
  datasource_files = [f for f in os.listdir(Path(folder) / "datasources") if f.endswith(".datasource")]
104
104
  for datasource_file in datasource_files:
105
105
  datasource_path = Path(folder) / "datasources" / datasource_file
106
- llm = LLM(user_token=user_token, client=tb_client)
106
+ llm = LLM(user_token=user_token, host=tb_client.host)
107
107
  datasource_name = datasource_path.stem
108
108
  datasource_content = datasource_path.read_text()
109
109
  has_json_path = "`json:" in datasource_content
110
110
  if has_json_path:
111
111
  prompt = f"<datasource_schema>{datasource_content}</datasource_schema>\n<user_input>{prompt}</user_input>"
112
- response = await llm.ask(system_prompt=mock_prompt(rows), prompt=prompt)
112
+ response = llm.ask(system_prompt=mock_prompt(rows), prompt=prompt)
113
113
  sql = extract_xml(response, "sql")
114
114
  sql = sql.split("FORMAT")[0]
115
115
  result = await local_client.query(f"{sql} FORMAT JSON")
@@ -205,8 +205,8 @@ TYPE ENDPOINT
205
205
  ]
206
206
  ]
207
207
  )
208
- llm = LLM(user_token=user_token, client=tb_client)
209
- result = await llm.ask(system_prompt=create_prompt(resources_xml), prompt=prompt)
208
+ llm = LLM(user_token=user_token, host=tb_client.host)
209
+ result = llm.ask(system_prompt=create_prompt(resources_xml), prompt=prompt)
210
210
  result = extract_xml(result, "response")
211
211
  resources = parse_xml(result, "resource")
212
212
  datasources = []
@@ -44,7 +44,7 @@ from tinybird.tb.modules.datafile.exceptions import AlreadyExistsException, Incl
44
44
  from tinybird.tb.modules.datafile.parse_datasource import parse_datasource
45
45
  from tinybird.tb.modules.datafile.parse_pipe import parse_pipe
46
46
  from tinybird.tb.modules.feedback_manager import FeedbackManager
47
- from tinybird.tb.modules.local_common import get_client_config_for_build
47
+ from tinybird.tb.modules.local_common import get_tinybird_local_config
48
48
 
49
49
 
50
50
  async def folder_build(
@@ -58,7 +58,7 @@ async def folder_build(
58
58
  local_ws: Optional[Dict[str, Any]] = None,
59
59
  watch: bool = False,
60
60
  ):
61
- config = await get_client_config_for_build(folder)
61
+ config = await get_tinybird_local_config(folder)
62
62
  build = True
63
63
  dry_run = False
64
64
  force = True
@@ -0,0 +1,32 @@
1
+ import requests
2
+
3
+
4
+ class LLM:
5
+ def __init__(
6
+ self,
7
+ host: str,
8
+ user_token: str,
9
+ ):
10
+ self.host = host
11
+ self.user_token = user_token
12
+
13
+ def ask(self, system_prompt: str, prompt: str) -> str:
14
+ """
15
+ Calls the model with the given prompt and returns the response.
16
+
17
+ Args:
18
+ system_prompt (str): The system prompt to send to the model.
19
+ prompt (str): The user prompt to send to the model.
20
+
21
+ Returns:
22
+ str: The response from the language model.
23
+ """
24
+
25
+ data = {"system": system_prompt, "prompt": prompt}
26
+
27
+ response = requests.post(
28
+ f"{self.host}/v0/llm",
29
+ headers={"Authorization": f"Bearer {self.user_token}"},
30
+ data=data,
31
+ )
32
+ return response.json().get("result", "")
@@ -0,0 +1,111 @@
1
+ import re
2
+ from typing import List
3
+
4
+
5
+ def extract_xml(text: str, tag: str) -> str:
6
+ """
7
+ Extracts the content of the specified XML tag from the given text. Used for parsing structured responses
8
+
9
+ Args:
10
+ text (str): The text containing the XML.
11
+ tag (str): The XML tag to extract content from.
12
+
13
+ Returns:
14
+ str: The content of the specified XML tag, or an empty string if the tag is not found.
15
+ """
16
+ match = re.search(f"<{tag}>(.*?)</{tag}>", text, re.DOTALL)
17
+ return match.group(1) if match else ""
18
+
19
+
20
+ def parse_xml(text: str, tag: str) -> List[str]:
21
+ """
22
+ Parses the text for the specified XML tag and returns a list of the contents of each tag.
23
+ """
24
+ return re.findall(f"<{tag}.*?>(.*?)</{tag}>", text, re.DOTALL)
25
+
26
+
27
+ def generate(llm_call, task: str, context: str = "") -> tuple[str, str]:
28
+ """Generate and improve a solution based on feedback."""
29
+ task = f"<task>\n{task}\n</task>"
30
+ full_prompt = (
31
+ f"{generator_prompt}\n<context>\n{context}\n</context>\n{task}" if context else f"{generator_prompt}\n{task}"
32
+ )
33
+ response = llm_call(full_prompt)
34
+ thoughts = extract_xml(response, "thoughts")
35
+ result = extract_xml(response, "response")
36
+
37
+ return thoughts, result
38
+
39
+
40
+ def evaluate(llm_call, content: str, task: str) -> tuple[str, str]:
41
+ """Evaluate if a solution meets requirements."""
42
+ full_prompt = f"{evaluator_prompt}\n<original_task>\n{task}\n</original_task>\n<content_to_evaluate>\n{content}\n</content_to_evaluate>"
43
+ response = llm_call(full_prompt)
44
+ evaluation = extract_xml(response, "evaluation")
45
+ feedback = extract_xml(response, "feedback")
46
+
47
+ return evaluation, feedback
48
+
49
+
50
+ def loop(llm_call, task: str) -> str:
51
+ """Keep generating and evaluating until requirements are met."""
52
+ memory = []
53
+ chain_of_thought = []
54
+
55
+ thoughts, result = generate(llm_call, task)
56
+ memory.append(result)
57
+ chain_of_thought.append({"thoughts": thoughts, "result": result})
58
+
59
+ attempts = 0
60
+ while True:
61
+ if attempts > 5:
62
+ raise Exception("Failed to generate a valid solution")
63
+
64
+ evaluation, feedback = evaluate(llm_call, result, task)
65
+ if evaluation == "PASS":
66
+ return result
67
+
68
+ context = "\n".join(
69
+ [
70
+ "Previous attempts:",
71
+ *[f"- {m}" for m in memory],
72
+ f"\nFeedback: {feedback}",
73
+ ]
74
+ )
75
+
76
+ thoughts, result = generate(llm_call, task, context)
77
+ memory.append(result)
78
+ chain_of_thought.append({"thoughts": thoughts, "result": result})
79
+
80
+ attempts += 1
81
+
82
+
83
+ evaluator_prompt = """
84
+ Evaluate this following code implementation for code correctness taking into account the user prompt and the instructions provided.
85
+
86
+ You should be evaluating only and not attemping to solve the task.
87
+ Only output "PASS" if all criteria are met and the code won't fail at runtime.
88
+ Output your evaluation concisely in the following format:
89
+
90
+ <evaluation>PASS or FAIL</evaluation>
91
+ <feedback>
92
+ [What is wrong with the code and how to fix it]
93
+ </feedback>
94
+ """
95
+
96
+ generator_prompt = """
97
+ Your goal is to complete the task based on <task> tag. If there are feedback
98
+ from your previous generations, you should reflect on them to improve your solution
99
+
100
+ Output your answer concisely in the following format:
101
+
102
+ <thoughts>
103
+ [Your understanding of the task and feedback and how you plan to improve]
104
+ </thoughts>
105
+
106
+ <response>
107
+ [Your code implementation here]
108
+ </response>
109
+
110
+ The code implementation should not be wrapped in any markdown format.
111
+ """
@@ -17,11 +17,11 @@ TB_LOCAL_HOST = f"http://localhost:{TB_LOCAL_PORT}"
17
17
 
18
18
  async def get_tinybird_local_client(path: Optional[str] = None) -> TinyB:
19
19
  """Get a Tinybird client connected to the local environment."""
20
- config = await get_client_config_for_build(path)
20
+ config = await get_tinybird_local_config(path)
21
21
  return config.get_client(host=TB_LOCAL_HOST)
22
22
 
23
23
 
24
- async def get_client_config_for_build(path: Optional[str] = None) -> CLIConfig:
24
+ async def get_tinybird_local_config(path: Optional[str] = None) -> CLIConfig:
25
25
  """Craft a client config with a workspace name based on the path of the project files
26
26
 
27
27
  It uses the tokens from tinybird local
@@ -24,7 +24,7 @@ from tinybird.tb.modules.local_common import get_tinybird_local_client
24
24
  default="Use the datasource schema to generate sample data",
25
25
  help="Extra context to use for data generation",
26
26
  )
27
- @click.option("--folder", type=str, default=".", help="Folder where datafiles will be placed")
27
+ @click.option("--folder", type=str, default=os.getcwd(), help="Folder where datafiles will be placed")
28
28
  @coro
29
29
  async def mock(datasource: str, rows: int, prompt: str, folder: str) -> None:
30
30
  """Load sample data into a Data Source.
@@ -67,11 +67,10 @@ async def mock(datasource: str, rows: int, prompt: str, folder: str) -> None:
67
67
  except Exception:
68
68
  click.echo(FeedbackManager.error(message="This action requires authentication. Run 'tb login' first."))
69
69
  return
70
- user_client.token = user_token
71
- llm = LLM(user_token=user_token, client=user_client)
70
+ llm = LLM(user_token=user_token, host=user_client.host)
72
71
  tb_client = await get_tinybird_local_client(os.path.abspath(folder))
73
72
  prompt = f"<datasource_schema>{datasource_content}</datasource_schema>\n<user_input>{prompt}</user_input>"
74
- response = await llm.ask(system_prompt=mock_prompt(rows), prompt=prompt)
73
+ response = llm.ask(system_prompt=mock_prompt(rows), prompt=prompt)
75
74
  sql = extract_xml(response, "sql")
76
75
  if os.environ.get("TB_DEBUG", "") != "":
77
76
  logging.debug(sql)
@@ -111,9 +111,9 @@ async def test_create(name_or_filename: str, prompt: str, folder: str) -> None:
111
111
  user_token = config.get_user_token()
112
112
  if not user_token:
113
113
  raise CLIException(FeedbackManager.error(message="No user token found"))
114
- llm = LLM(user_token=user_token, client=config.get_client())
114
+ llm = LLM(user_token=user_token, host=config.get_client().host)
115
115
 
116
- response_llm = await llm.ask(system_prompt=system_prompt, prompt=prompt)
116
+ response_llm = llm.ask(system_prompt=system_prompt, prompt=prompt)
117
117
  response_xml = extract_xml(response_llm, "response")
118
118
  tests_content = parse_xml(response_xml, "test")
119
119
 
@@ -65,13 +65,13 @@ async def update(
65
65
  datasource_files = [f for f in os.listdir(Path(folder) / "datasources") if f.endswith(".datasource")]
66
66
  for datasource_file in datasource_files:
67
67
  datasource_path = Path(folder) / "datasources" / datasource_file
68
- llm = LLM(user_token=user_token, client=tb_client)
68
+ llm = LLM(user_token=user_token, host=tb_client.host)
69
69
  datasource_name = datasource_path.stem
70
70
  datasource_content = datasource_path.read_text()
71
71
  has_json_path = "`json:" in datasource_content
72
72
  if has_json_path:
73
73
  prompt = f"<datasource_schema>{datasource_content}</datasource_schema>\n<user_input>{prompt}</user_input>"
74
- response = await llm.ask(system_prompt=mock_prompt(rows=20), prompt=prompt)
74
+ response = llm.ask(system_prompt=mock_prompt(rows=20), prompt=prompt)
75
75
  sql = extract_xml(response, "sql")
76
76
  sql = sql.split("FORMAT")[0]
77
77
  result = await local_client.query(f"{sql} FORMAT JSON")
@@ -116,8 +116,8 @@ async def update_resources(
116
116
  ]
117
117
  ]
118
118
  )
119
- llm = LLM(user_token=user_token, client=tb_client)
120
- result = await llm.ask(system_prompt=update_prompt(resources_xml), prompt=prompt)
119
+ llm = LLM(user_token=user_token, host=tb_client.host)
120
+ result = llm.ask(system_prompt=update_prompt(resources_xml), prompt=prompt)
121
121
  result = extract_xml(result, "response")
122
122
  resources = parse_xml(result, "resource")
123
123
  datasources = []
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tinybird
3
- Version: 0.0.1.dev35
3
+ Version: 0.0.1.dev36
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -1,38 +0,0 @@
1
- from copy import deepcopy
2
- from typing import Optional
3
-
4
- from tinybird.client import TinyB
5
-
6
-
7
- class LLM:
8
- def __init__(
9
- self,
10
- user_token: str,
11
- client: TinyB,
12
- ):
13
- self.user_client = deepcopy(client)
14
- self.user_client.token = user_token
15
-
16
- async def ask(self, system_prompt: str, prompt: Optional[str] = None) -> str:
17
- """
18
- Calls the model with the given prompt and returns the response.
19
-
20
- Args:
21
- system_prompt (str): The system prompt to send to the model.
22
- prompt (str): The user prompt to send to the model.
23
-
24
- Returns:
25
- str: The response from the language model.
26
- """
27
-
28
- data = {"system": system_prompt}
29
-
30
- if prompt:
31
- data["prompt"] = prompt
32
-
33
- response = await self.user_client._req(
34
- "/v0/llm",
35
- method="POST",
36
- data=data,
37
- )
38
- return response.get("result", "")
@@ -1,24 +0,0 @@
1
- import re
2
- from typing import List
3
-
4
-
5
- def extract_xml(text: str, tag: str) -> str:
6
- """
7
- Extracts the content of the specified XML tag from the given text. Used for parsing structured responses
8
-
9
- Args:
10
- text (str): The text containing the XML.
11
- tag (str): The XML tag to extract content from.
12
-
13
- Returns:
14
- str: The content of the specified XML tag, or an empty string if the tag is not found.
15
- """
16
- match = re.search(f"<{tag}>(.*?)</{tag}>", text, re.DOTALL)
17
- return match.group(1) if match else ""
18
-
19
-
20
- def parse_xml(text: str, tag: str) -> List[str]:
21
- """
22
- Parses the text for the specified XML tag and returns a list of the contents of each tag.
23
- """
24
- return re.findall(f"<{tag}.*?>(.*?)</{tag}>", text, re.DOTALL)
File without changes