tinybird 0.0.1.dev14__tar.gz → 0.0.1.dev15__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 (95) hide show
  1. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/PKG-INFO +1 -1
  2. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/datafile.py +3 -3
  3. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/cli.py +0 -1
  4. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/build.py +67 -18
  5. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/cli.py +6 -20
  6. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/create.py +5 -9
  7. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/datafile/build.py +29 -21
  8. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/datafile/build_pipe.py +4 -0
  9. tinybird-0.0.1.dev15/tinybird/tb/modules/datafile/common.py +1850 -0
  10. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/datafile/parse_datasource.py +1 -0
  11. tinybird-0.0.1.dev15/tinybird/tb/modules/llm.py +63 -0
  12. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/local.py +3 -4
  13. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/login.py +0 -1
  14. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/mock.py +5 -4
  15. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/prompts.py +23 -1
  16. tinybird-0.0.1.dev15/tinybird/tb/modules/test.py +127 -0
  17. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird.egg-info/PKG-INFO +1 -1
  18. tinybird-0.0.1.dev14/tinybird/tb/modules/datafile/common.py +0 -910
  19. tinybird-0.0.1.dev14/tinybird/tb/modules/llm.py +0 -73
  20. tinybird-0.0.1.dev14/tinybird/tb/modules/test.py +0 -107
  21. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/setup.cfg +0 -0
  22. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/__cli__.py +0 -0
  23. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/ch_utils/constants.py +0 -0
  24. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/ch_utils/engine.py +0 -0
  25. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/check_pypi.py +0 -0
  26. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/client.py +0 -0
  27. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/config.py +0 -0
  28. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/connectors.py +0 -0
  29. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/context.py +0 -0
  30. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/datatypes.py +0 -0
  31. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/feedback_manager.py +0 -0
  32. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/git_settings.py +0 -0
  33. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/sql.py +0 -0
  34. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/sql_template.py +0 -0
  35. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/sql_template_fmt.py +0 -0
  36. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/sql_toolset.py +0 -0
  37. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/syncasync.py +0 -0
  38. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/auth.py +0 -0
  39. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/branch.py +0 -0
  40. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/cicd.py +0 -0
  41. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/common.py +0 -0
  42. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/config.py +0 -0
  43. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/connection.py +0 -0
  44. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/datafile/build_common.py +0 -0
  45. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  46. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/datafile/diff.py +0 -0
  47. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/datafile/exceptions.py +0 -0
  48. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/datafile/fixture.py +0 -0
  49. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/datafile/format_common.py +0 -0
  50. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  51. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  52. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/datafile/parse_pipe.py +0 -0
  53. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  54. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/datafile/pull.py +0 -0
  55. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/datasource.py +0 -0
  56. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/exceptions.py +0 -0
  57. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/fmt.py +0 -0
  58. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/job.py +0 -0
  59. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/pipe.py +0 -0
  60. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/regions.py +0 -0
  61. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/table.py +0 -0
  62. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/tag.py +0 -0
  63. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/telemetry.py +0 -0
  64. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  65. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  66. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/token.py +0 -0
  67. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/workspace.py +0 -0
  68. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb/modules/workspace_members.py +0 -0
  69. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli.py +0 -0
  70. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/auth.py +0 -0
  71. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/branch.py +0 -0
  72. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/cicd.py +0 -0
  73. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/cli.py +0 -0
  74. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/common.py +0 -0
  75. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/config.py +0 -0
  76. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/connection.py +0 -0
  77. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/datasource.py +0 -0
  78. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/exceptions.py +0 -0
  79. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/fmt.py +0 -0
  80. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/job.py +0 -0
  81. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/pipe.py +0 -0
  82. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/regions.py +0 -0
  83. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/tag.py +0 -0
  84. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/telemetry.py +0 -0
  85. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/test.py +0 -0
  86. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  87. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  88. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/workspace.py +0 -0
  89. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  90. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird/tornado_template.py +0 -0
  91. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird.egg-info/SOURCES.txt +0 -0
  92. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird.egg-info/dependency_links.txt +0 -0
  93. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird.egg-info/entry_points.txt +0 -0
  94. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/tinybird.egg-info/requires.txt +0 -0
  95. {tinybird-0.0.1.dev14 → tinybird-0.0.1.dev15}/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.dev14
3
+ Version: 0.0.1.dev15
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -1051,9 +1051,9 @@ def parse(
1051
1051
  def _f(sql: str, **kwargs: Any) -> None:
1052
1052
  if not parser_state.current_node:
1053
1053
  raise ParseException("SQL must be called after a NODE command")
1054
- parser_state.current_node[var_name] = (
1055
- textwrap.dedent(sql).rstrip() if "%" not in sql.strip()[0] else sql.strip()
1056
- )
1054
+ _sql = textwrap.dedent(sql).rstrip() if "%" not in sql.strip()[0] else sql.strip()
1055
+ _sql = eval_var(_sql)
1056
+ parser_state.current_node[var_name] = _sql
1057
1057
 
1058
1058
  # HACK this cast is needed because Mypy
1059
1059
  return cast(Callable[[str, KwArg(Any)], None], _f)
@@ -18,7 +18,6 @@ import tinybird.tb.modules.login
18
18
  import tinybird.tb.modules.mock
19
19
  import tinybird.tb.modules.pipe
20
20
  import tinybird.tb.modules.tag
21
- import tinybird.tb.modules.test
22
21
  import tinybird.tb.modules.token
23
22
  import tinybird.tb.modules.workspace
24
23
  import tinybird.tb.modules.workspace_members
@@ -11,11 +11,14 @@ from typing import Any, Awaitable, Callable, List, Union
11
11
 
12
12
  import click
13
13
  import humanfriendly
14
+ from click import Context
14
15
  from watchdog.events import FileSystemEventHandler
15
16
  from watchdog.observers import Observer
16
17
 
17
18
  import tinybird.context as context
18
- from tinybird.client import TinyB
19
+ from tinybird.syncasync import async_to_sync
20
+ from tinybird.client import TinyB, AuthNoTokenException
21
+ from tinybird.tb.modules.common import CLIException
19
22
  from tinybird.config import FeatureFlags
20
23
  from tinybird.feedback_manager import FeedbackManager, bcolors
21
24
  from tinybird.tb.modules.cli import cli
@@ -33,10 +36,10 @@ from tinybird.tb.modules.table import format_table
33
36
  class BuildShell(cmd.Cmd):
34
37
  prompt = "\n\001\033[1;32m\002TB > \001\033[0m\002"
35
38
 
36
- def __init__(self, folder: str):
39
+ def __init__(self, folder: str, client: TinyB):
37
40
  super().__init__()
38
41
  self.folder = folder
39
-
42
+ self.client = client
40
43
  def do_exit(self, arg):
41
44
  sys.exit(0)
42
45
 
@@ -55,7 +58,11 @@ class BuildShell(cmd.Cmd):
55
58
  extra_args = f" --folder {self.folder}" if arg_stripped.startswith("tb mock") else ""
56
59
  subprocess.run(arg_stripped + extra_args, shell=True, text=True)
57
60
  elif arg_stripped.startswith("with") or arg_stripped.startswith("select"):
58
- subprocess.run(f'tb sql "{arg_stripped}"', shell=True, text=True)
61
+ try:
62
+ run_sql(self.client, argline)
63
+ except Exception as e:
64
+ click.echo(FeedbackManager.error(message=str(e)))
65
+
59
66
  elif arg_stripped.startswith("mock "):
60
67
  subprocess.run(f"tb {arg_stripped} --folder {self.folder}", shell=True, text=True)
61
68
  else:
@@ -72,7 +79,12 @@ class FileChangeHandler(FileSystemEventHandler):
72
79
  self.process = process
73
80
 
74
81
  def on_modified(self, event: Any) -> None:
75
- if not event.is_directory and any(event.src_path.endswith(ext) for ext in [".datasource", ".pipe", ".ndjson"]):
82
+ is_not_vendor = "vendor/" not in event.src_path
83
+ if (
84
+ is_not_vendor
85
+ and not event.is_directory
86
+ and any(event.src_path.endswith(ext) for ext in [".datasource", ".pipe", ".ndjson"])
87
+ ):
76
88
  filename = event.src_path.split("/")[-1]
77
89
  click.echo(FeedbackManager.highlight(message=f"\n\n⟲ Changes detected in {filename}\n"))
78
90
  try:
@@ -119,6 +131,44 @@ def watch_files(
119
131
  observer.join()
120
132
 
121
133
 
134
+
135
+ def run_sql(client: TinyB, query, rows_limit=20):
136
+ try:
137
+ q = query.strip()
138
+ if q.startswith("insert"):
139
+ click.echo(FeedbackManager.info_append_data())
140
+ raise CLIException(FeedbackManager.error_invalid_query())
141
+ if q.startswith("delete"):
142
+ raise CLIException(FeedbackManager.error_invalid_query())
143
+
144
+ # fuck my life
145
+ def run_query_in_thread():
146
+ loop = asyncio.new_event_loop()
147
+ asyncio.set_event_loop(loop)
148
+ try:
149
+ return loop.run_until_complete(client.query(f"SELECT * FROM ({query}) LIMIT {rows_limit} FORMAT JSON"))
150
+ finally:
151
+ loop.close()
152
+
153
+ # Run the query in a separate thread
154
+ import concurrent.futures
155
+ with concurrent.futures.ThreadPoolExecutor() as executor:
156
+ res = executor.submit(run_query_in_thread).result()
157
+
158
+ except AuthNoTokenException:
159
+ raise
160
+ except Exception as e:
161
+ raise CLIException(FeedbackManager.error_exception(error=str(e)))
162
+
163
+ if isinstance(res, dict) and "error" in res:
164
+ raise CLIException(FeedbackManager.error_exception(error=res["error"]))
165
+
166
+ if isinstance(res, dict) and "data" in res and res["data"]:
167
+ print_table_formatted(res, 'QUERY')
168
+ else:
169
+ click.echo(FeedbackManager.info_no_rows())
170
+
171
+
122
172
  @cli.command()
123
173
  @click.option(
124
174
  "--folder",
@@ -132,16 +182,12 @@ def watch_files(
132
182
  is_flag=True,
133
183
  help="Watch for changes in the files and re-check them.",
134
184
  )
135
- @click.option(
136
- "--skip-datasources",
137
- is_flag=True,
138
- help="Skip rebuilding datasources.",
139
- )
185
+ @click.pass_context
140
186
  @coro
141
187
  async def build(
188
+ ctx: Context,
142
189
  folder: str,
143
190
  watch: bool,
144
- skip_datasources: bool,
145
191
  ) -> None:
146
192
  """
147
193
  Watch for changes in the files and re-check them.
@@ -171,7 +217,7 @@ async def build(
171
217
 
172
218
  parser(filename)
173
219
 
174
- async def process(filenames: List[str], watch: bool = False, only_pipes: bool = False):
220
+ async def process(filenames: List[str], watch: bool = False):
175
221
  datafiles = [f for f in filenames if f.endswith(".datasource") or f.endswith(".pipe")]
176
222
  if len(datafiles) > 0:
177
223
  check_filenames(filenames=datafiles)
@@ -180,7 +226,7 @@ async def build(
180
226
  filenames=datafiles,
181
227
  ignore_sql_errors=ignore_sql_errors,
182
228
  is_internal=is_internal,
183
- only_pipes=only_pipes,
229
+ watch=watch,
184
230
  )
185
231
 
186
232
  filename = filenames[0]
@@ -209,7 +255,7 @@ async def build(
209
255
  try:
210
256
  click.echo("⚡ Building project...\n")
211
257
  time_start = time.time()
212
- await process(filenames=filenames, watch=False, only_pipes=skip_datasources)
258
+ await process(filenames=filenames, watch=False)
213
259
  time_end = time.time()
214
260
  elapsed_time = time_end - time_start
215
261
  for filename in filenames:
@@ -226,7 +272,7 @@ async def build(
226
272
  await build_once(filenames)
227
273
 
228
274
  if watch:
229
- shell = BuildShell(folder=folder)
275
+ shell = BuildShell(folder=folder, client=tb_client)
230
276
  click.echo(FeedbackManager.highlight(message="◎ Watching for changes..."))
231
277
  watcher_thread = threading.Thread(target=watch_files, args=(filenames, process, shell, folder), daemon=True)
232
278
  watcher_thread.start()
@@ -234,13 +280,16 @@ async def build(
234
280
 
235
281
 
236
282
  async def build_and_print_resource(tb_client: TinyB, filename: str):
237
- rebuild_colors = [bcolors.FAIL, bcolors.OKBLUE, bcolors.WARNING, bcolors.OKGREEN, bcolors.HEADER]
238
- rebuild_index = random.randint(0, len(rebuild_colors) - 1)
239
- rebuild_color = rebuild_colors[rebuild_index % len(rebuild_colors)]
240
283
  resource_path = Path(filename)
241
284
  name = resource_path.stem
242
285
  pipeline = name if filename.endswith(".pipe") else None
243
286
  res = await tb_client.query(f"SELECT * FROM {name} FORMAT JSON", pipeline=pipeline)
287
+ print_table_formatted(res, name)
288
+
289
+ def print_table_formatted(res: dict, name: str):
290
+ rebuild_colors = [bcolors.FAIL, bcolors.OKBLUE, bcolors.WARNING, bcolors.OKGREEN, bcolors.HEADER]
291
+ rebuild_index = random.randint(0, len(rebuild_colors) - 1)
292
+ rebuild_color = rebuild_colors[rebuild_index % len(rebuild_colors)]
244
293
  data = []
245
294
  limit = 5
246
295
  for d in res["data"][:5]:
@@ -10,7 +10,7 @@ import pprint
10
10
  import re
11
11
  import shutil
12
12
  import sys
13
- from os import environ, getcwd
13
+ from os import getcwd
14
14
  from pathlib import Path
15
15
  from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union
16
16
 
@@ -26,7 +26,7 @@ from tinybird.client import (
26
26
  DoesNotExistException,
27
27
  TinyB,
28
28
  )
29
- from tinybird.config import CURRENT_VERSION, SUPPORTED_CONNECTORS, VERSION, FeatureFlags, get_config
29
+ from tinybird.config import SUPPORTED_CONNECTORS, VERSION, FeatureFlags, get_config
30
30
  from tinybird.feedback_manager import FeedbackManager
31
31
  from tinybird.tb.modules.common import (
32
32
  OLDEST_ROLLBACK,
@@ -50,6 +50,7 @@ from tinybird.tb.modules.config import CLIConfig
50
50
  from tinybird.tb.modules.datafile.build import build_graph, folder_push
51
51
  from tinybird.tb.modules.datafile.common import (
52
52
  Datafile,
53
+ DatafileSyntaxError,
53
54
  get_project_filenames,
54
55
  get_resource_versions,
55
56
  has_internal_datafiles,
@@ -106,12 +107,6 @@ DEFAULT_PATTERNS: List[Tuple[str, Union[str, Callable[[str], str]]]] = [
106
107
  @click.option(
107
108
  "--with-headers", help="Flag to enable connector to export with headers", is_flag=True, default=False, hidden=True
108
109
  )
109
- @click.option(
110
- "--version-warning/--no-version-warning",
111
- envvar="TB_VERSION_WARNING",
112
- default=True,
113
- help="Don't print version warning message if there's a new available version. You can use TB_VERSION_WARNING envar",
114
- )
115
110
  @click.option("--show-tokens", is_flag=True, default=False, help="Enable the output of tokens")
116
111
  @click.version_option(version=VERSION)
117
112
  @click.pass_context
@@ -135,7 +130,6 @@ async def cli(
135
130
  sf_storage_integration: str,
136
131
  sf_stage,
137
132
  with_headers: bool,
138
- version_warning: bool,
139
133
  show_tokens: bool,
140
134
  ) -> None:
141
135
  """
@@ -151,17 +145,6 @@ async def cli(
151
145
  if getenv_bool("TB_DISABLE_SSL_CHECKS", False):
152
146
  click.echo(FeedbackManager.warning_disabled_ssl_checks())
153
147
 
154
- # ensure that ctx.obj exists and is a dict (in case `cli()` is called)
155
- # by means other than the `if` block below
156
- if not environ.get("PYTEST", None) and version_warning and not token:
157
- from tinybird.check_pypi import CheckPypi
158
-
159
- latest_version = await CheckPypi().get_latest_version()
160
-
161
- if "x.y.z" not in CURRENT_VERSION and latest_version != CURRENT_VERSION:
162
- click.echo(FeedbackManager.warning_update_version(latest_version=latest_version))
163
- click.echo(FeedbackManager.warning_current_version(current_version=CURRENT_VERSION))
164
-
165
148
  if debug:
166
149
  logging.basicConfig(level=logging.DEBUG)
167
150
 
@@ -361,6 +344,9 @@ def check(filenames: List[str], debug: bool) -> None:
361
344
  for x in doc.nodes:
362
345
  pp.pprint(x)
363
346
 
347
+ except DatafileSyntaxError as e:
348
+ # TODO(eclbg): add the filename to the error message
349
+ raise CLIException(e)
364
350
  except ParseException as e:
365
351
  raise CLIException(FeedbackManager.error_exception(error=e))
366
352
 
@@ -16,7 +16,6 @@ from tinybird.tb.modules.config import CLIConfig
16
16
  from tinybird.tb.modules.datafile.fixture import build_fixture_name, persist_fixture
17
17
  from tinybird.tb.modules.exceptions import CLIException
18
18
  from tinybird.tb.modules.llm import LLM
19
- from tinybird.tb.modules.local import get_tinybird_local_client
20
19
 
21
20
 
22
21
  @cli.command()
@@ -51,7 +50,8 @@ async def create(
51
50
  """Initialize a new project."""
52
51
  folder = folder or getcwd()
53
52
  try:
54
- tb_client = await get_tinybird_local_client(os.path.abspath(folder))
53
+ config = CLIConfig.get_project_config()
54
+ tb_client = config.get_client()
55
55
  click.echo(FeedbackManager.gray(message="Creating new project structure..."))
56
56
  await project_create(tb_client, data, prompt, folder)
57
57
  click.echo(FeedbackManager.success(message="✓ Scaffolding completed!\n"))
@@ -74,13 +74,12 @@ async def create(
74
74
  datasource_files = [f for f in os.listdir(Path(folder) / "datasources") if f.endswith(".datasource")]
75
75
  for datasource_file in datasource_files:
76
76
  datasource_path = Path(folder) / "datasources" / datasource_file
77
- llm_config = CLIConfig.get_llm_config()
78
- llm = LLM(key=llm_config["api_key"])
77
+ llm = LLM(client=tb_client)
79
78
  datasource_name = datasource_path.stem
80
79
  datasource_content = datasource_path.read_text()
81
80
  has_json_path = "`json:" in datasource_content
82
81
  if has_json_path:
83
- sql = await llm.generate_sql_sample_data(tb_client, datasource_name, datasource_content, rows)
82
+ sql = await llm.generate_sql_sample_data(schema=datasource_content, rows=rows)
84
83
  result = await tb_client.query(f"{sql} FORMAT JSON")
85
84
  data = result.get("data", [])
86
85
  fixture_name = build_fixture_name(datasource_path.absolute(), datasource_name, datasource_content)
@@ -88,8 +87,6 @@ async def create(
88
87
  click.echo(FeedbackManager.info(message=f"✓ /fixtures/{datasource_name}"))
89
88
 
90
89
  click.echo(FeedbackManager.success(message="✓ Done!\n"))
91
-
92
- click.echo(FeedbackManager.success(message="✓ Tinybird local is ready!"))
93
90
  except Exception as e:
94
91
  click.echo(FeedbackManager.error(message=f"Error: {str(e)}"))
95
92
 
@@ -130,8 +127,7 @@ TYPE ENDPOINT
130
127
  )
131
128
  elif prompt:
132
129
  try:
133
- llm_config = CLIConfig.get_llm_config()
134
- llm = LLM(key=llm_config["api_key"])
130
+ llm = LLM(client=client)
135
131
  result = await llm.create_project(prompt)
136
132
  for ds in result.datasources:
137
133
  content = ds.content.replace("```", "")
@@ -54,15 +54,12 @@ async def folder_build(
54
54
  folder: str = ".",
55
55
  ignore_sql_errors: bool = False,
56
56
  is_internal: bool = False,
57
- only_pipes: bool = False,
58
57
  is_vendor: bool = False,
59
58
  current_ws: Optional[Dict[str, Any]] = None,
60
59
  local_ws: Optional[Dict[str, Any]] = None,
61
60
  workspaces: Optional[List[Dict[str, Any]]] = None,
61
+ watch: bool = False,
62
62
  ):
63
- if only_pipes:
64
- filenames = [f for f in filenames if f.endswith(".pipe")]
65
-
66
63
  config = CLIConfig.get_project_config()
67
64
  build = True
68
65
  dry_run = False
@@ -118,7 +115,7 @@ async def folder_build(
118
115
 
119
116
  vendor_workspaces = []
120
117
 
121
- if vendor_path.exists() and not is_vendor:
118
+ if vendor_path.exists() and not is_vendor and not watch:
122
119
  user_workspaces = await user_client.user_workspaces()
123
120
  for x in vendor_path.iterdir():
124
121
  if x.is_dir() and x.name not in existing_workspaces:
@@ -147,7 +144,7 @@ async def folder_build(
147
144
  ws_client.token = vendor_ws["token"]
148
145
  shared_ws_path = Path(folder) / "vendor" / vendor_ws["name"]
149
146
 
150
- if shared_ws_path.exists() and not is_vendor:
147
+ if shared_ws_path.exists() and not is_vendor and not watch:
151
148
  await folder_build(
152
149
  ws_client, folder=shared_ws_path.as_posix(), is_vendor=True, current_ws=vendor_ws, local_ws=local_ws
153
150
  )
@@ -440,14 +437,16 @@ async def folder_build(
440
437
 
441
438
  for group in groups:
442
439
  for name in group:
443
- try:
444
- await tb_client.datasource_delete(name, force=True)
445
- except Exception:
446
- pass
447
- try:
448
- await tb_client.pipe_delete(name)
449
- except Exception:
450
- pass
440
+ is_vendor = resources_to_run_fork_downstream.get(name, {}).get("filename", "").startswith("vendor/")
441
+ if not is_vendor:
442
+ try:
443
+ await tb_client.datasource_delete(name, force=True)
444
+ except Exception:
445
+ pass
446
+ try:
447
+ await tb_client.pipe_delete(name)
448
+ except Exception:
449
+ pass
451
450
 
452
451
  groups.reverse()
453
452
  for group in groups:
@@ -1036,9 +1035,13 @@ async def build_graph(
1036
1035
  raise click.ClickException(str(e))
1037
1036
 
1038
1037
  for r in res:
1039
- fn = r["resource_name"]
1038
+ resource_name = r["resource_name"]
1040
1039
  warnings = r.get("warnings", [])
1041
- if changed and fn in changed and (not changed[fn] or changed[fn] in ["shared", "remote"]):
1040
+ if (
1041
+ changed
1042
+ and resource_name in changed
1043
+ and (not changed[resource_name] or changed[resource_name] in ["shared", "remote"])
1044
+ ):
1042
1045
  continue
1043
1046
 
1044
1047
  if (
@@ -1046,9 +1049,9 @@ async def build_graph(
1046
1049
  and r.get("resource", "") == "pipes"
1047
1050
  and any(["engine" in x.get("params", {}) for x in r.get("nodes", [])])
1048
1051
  ):
1049
- raise click.ClickException(FeedbackManager.error_forkdownstream_pipes_with_engine(pipe=fn))
1052
+ raise click.ClickException(FeedbackManager.error_forkdownstream_pipes_with_engine(pipe=resource_name))
1050
1053
 
1051
- to_run[fn] = r
1054
+ to_run[resource_name] = r
1052
1055
  file_deps = r.get("deps", [])
1053
1056
  deps += file_deps
1054
1057
  # calculate and look for deps
@@ -1064,7 +1067,7 @@ async def build_graph(
1064
1067
  to_run[ds_fn] = deepcopy(r)
1065
1068
  try:
1066
1069
  to_run[ds_fn]["deps"] = list(
1067
- set(to_run[ds_fn].get("deps", []) + prev.get("deps", []) + [fn])
1070
+ set(to_run[ds_fn].get("deps", []) + prev.get("deps", []) + [resource_name])
1068
1071
  )
1069
1072
  except ValueError:
1070
1073
  pass
@@ -1085,7 +1088,7 @@ async def build_graph(
1085
1088
  )
1086
1089
  r["shared_with"] = mapped_workspaces
1087
1090
 
1088
- dep_map[fn] = set(dep_list)
1091
+ dep_map[resource_name] = set(dep_list)
1089
1092
  return os.path.basename(name), warnings
1090
1093
 
1091
1094
  processed = set()
@@ -1169,7 +1172,10 @@ async def process_file(
1169
1172
  workspace_map: Optional[Dict] = None,
1170
1173
  workspace_lib_paths: Optional[List[Tuple[str, str]]] = None,
1171
1174
  current_ws: Optional[Dict[str, Any]] = None,
1172
- ):
1175
+ ) -> List[Dict[str, Any]]:
1176
+ """Returns a list of resources
1177
+
1178
+ For both datasources and pipes, a list of just one item is returned"""
1173
1179
  if workspace_map is None:
1174
1180
  workspace_map = {}
1175
1181
 
@@ -1349,6 +1355,8 @@ async def process_file(
1349
1355
  indexes = None
1350
1356
  if indexes_list:
1351
1357
  indexes = "\n".join([index.to_sql() for index in indexes_list])
1358
+ # Here is where we lose the columns
1359
+ # I don't know why we don't return something more similar to the parsed doc
1352
1360
  params = {
1353
1361
  "name": append_version_to_name(name, version),
1354
1362
  "description": description,
@@ -264,6 +264,10 @@ async def new_pipe(
264
264
  except Exception as e:
265
265
  raise click.ClickException(FeedbackManager.error_creating_pipe(error=e))
266
266
 
267
+ if data.get("type") == "endpoint":
268
+ token = tb_client.token
269
+ print(f"""** => Test endpoint with:\n** $ curl {host}/v0/pipes/{p["name"]}.json?token={token}""") # noqa: T201
270
+
267
271
 
268
272
  async def get_token_from_main_branch(branch_tb_client: TinyB) -> Optional[str]:
269
273
  token_from_main_branch = None