tinybird 0.0.1.dev72__py3-none-any.whl → 0.0.1.dev74__py3-none-any.whl

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.

@@ -33,7 +33,7 @@ from tinybird.tb.modules.project import Project
33
33
  @cli.group()
34
34
  @click.pass_context
35
35
  def datasource(ctx):
36
- """Data Source commands"""
36
+ """Data source commands."""
37
37
 
38
38
 
39
39
  @datasource.command(name="ls")
@@ -339,36 +339,34 @@ def create_deployment(
339
339
  result = r.json()
340
340
  logging.debug(json.dumps(result, indent=2))
341
341
 
342
- if check:
343
- print_changes(result, project)
344
- feedback = result.get("deployment", {}).get("feedback", [])
345
- for f in feedback:
342
+ print_changes(result, project)
343
+
344
+ feedback = result.get("deployment", {}).get("feedback", [])
345
+ for f in feedback:
346
+ click.echo(FeedbackManager.warning(message=f"△ {f.get('level')}: {f.get('resource')}: {f.get('message')}"))
347
+
348
+ deploy_errors = result.get("deployment", {}).get("errors")
349
+ for deploy_error in deploy_errors:
350
+ if deploy_error.get("filename", None):
346
351
  click.echo(
347
- FeedbackManager.warning(message=f"{f.get('level')}: {f.get('resource')}: {f.get('message')}")
352
+ FeedbackManager.error(message=f"{deploy_error.get('filename')}\n\n{deploy_error.get('error')}")
348
353
  )
354
+ else:
355
+ click.echo(FeedbackManager.error(message=f"{deploy_error.get('error')}"))
349
356
 
350
- status = result.get("result")
357
+ status = result.get("result")
358
+ if check:
351
359
  if status == "success":
352
360
  click.echo(FeedbackManager.success(message="\n✓ Deployment is valid"))
353
- else:
354
- click.echo(FeedbackManager.error(message="\n✗ Deployment is not valid"))
355
- deploy_errors = result.get("errors")
356
- for deploy_error in deploy_errors:
357
- if deploy_error.get("filename", None):
358
- click.echo(
359
- FeedbackManager.error(
360
- message=f"{deploy_error.get('filename')}\n\n{deploy_error.get('error')}"
361
- )
362
- )
363
- else:
364
- click.echo(FeedbackManager.error(message=f"{deploy_error.get('error')}"))
365
- return
366
-
367
- deploy_result = result.get("result")
368
- if deploy_result == "success":
369
- print_changes(result, project)
361
+ sys.exit(0)
362
+
363
+ click.echo(FeedbackManager.error(message="\n✗ Deployment is not valid"))
364
+ sys.exit(1)
365
+
366
+ status = result.get("result")
367
+ if status == "success":
370
368
  deployment = result.get("deployment", {})
371
- # We show the url in the case of region is public
369
+ # TODO: This is a hack to show the url in the case of region is public. The URL should be returned by the API
372
370
  if client.host == "https://api.europe-west2.gcp.tinybird.co":
373
371
  click.echo(
374
372
  FeedbackManager.gray(message="Deployment URL: ")
@@ -381,25 +379,10 @@ def create_deployment(
381
379
  click.echo(FeedbackManager.info(message="\n✓ Deployment submitted successfully"))
382
380
  else:
383
381
  click.echo(FeedbackManager.success(message="\n✓ Deployment submitted successfully"))
384
-
385
- feedback = deployment.get("feedback", [])
386
- for f in feedback:
387
- click.echo(
388
- FeedbackManager.warning(message=f"△ {f.get('level')}: {f.get('resource')}: {f.get('message')}")
389
- )
390
-
391
- elif deploy_result == "failed":
382
+ elif status == "failed":
392
383
  click.echo(FeedbackManager.error(message="Deployment failed"))
393
- deploy_errors = result.get("errors")
394
- for deploy_error in deploy_errors:
395
- if deploy_error.get("filename", None):
396
- click.echo(
397
- FeedbackManager.error(message=f"{deploy_error.get('filename')}\n\n{deploy_error.get('error')}")
398
- )
399
- else:
400
- click.echo(FeedbackManager.error(message=f"{deploy_error.get('error')}"))
401
384
  else:
402
- click.echo(FeedbackManager.error(message=f"Unknown build result {deploy_result}"))
385
+ click.echo(FeedbackManager.error(message=f"Unknown build result {status}"))
403
386
  except Exception as e:
404
387
  click.echo(FeedbackManager.error_exception(error=e))
405
388
  finally:
@@ -25,7 +25,7 @@ from tinybird.tb.modules.feedback_manager import FeedbackManager
25
25
  @cli.group()
26
26
  @click.pass_context
27
27
  def endpoint(ctx):
28
- """Endpoint commands"""
28
+ """Endpoint commands."""
29
29
 
30
30
 
31
31
  @endpoint.command(name="ls")
@@ -38,13 +38,13 @@ async def fmt(
38
38
  ctx: Context, filenames: List[str], line_length: int, dry_run: bool, yes: bool, diff: bool
39
39
  ) -> Optional[str]:
40
40
  """
41
- Formats a .datasource, .pipe or .incl file
41
+ Formats a .datasource, .pipe or .incl file.
42
42
 
43
43
  This command removes comments starting with # from the file, use DESCRIPTION instead.
44
44
 
45
45
  The format command tries to parse the datafile so syntax errors might rise.
46
46
 
47
- .incl files must contain a NODE definition
47
+ .incl files must contain a NODE definition.
48
48
  """
49
49
 
50
50
  result = ""
@@ -109,7 +109,7 @@ def remove_tinybird_local(docker_client):
109
109
 
110
110
  @cli.command()
111
111
  def upgrade():
112
- """Upgrade Tinybird CLI to the latest version"""
112
+ """Upgrade Tinybird CLI to the latest version."""
113
113
  click.echo(FeedbackManager.highlight(message="» Upgrading Tinybird CLI..."))
114
114
  process = subprocess.Popen(
115
115
  [f"{os.getenv('HOME')}/.local/bin/uv", "tool", "upgrade", "tinybird"],
@@ -127,7 +127,7 @@ def upgrade():
127
127
  @cli.group()
128
128
  @click.pass_context
129
129
  def local(ctx):
130
- """Local commands"""
130
+ """Manage the local Tinybird instance."""
131
131
 
132
132
 
133
133
  @local.command()
@@ -19,7 +19,7 @@ from tinybird.tb.modules.feedback_manager import FeedbackManager
19
19
  @cli.group()
20
20
  @click.pass_context
21
21
  def materialization(ctx):
22
- """Materialization commands"""
22
+ """Materialization commands."""
23
23
 
24
24
 
25
25
  @materialization.command(name="ls")
@@ -27,7 +27,7 @@ from tinybird.tb.modules.project import Project
27
27
  @click.pass_context
28
28
  @coro
29
29
  async def mock(ctx: click.Context, datasource: str, rows: int, prompt: str) -> None:
30
- """Generate sample data for a datasource.
30
+ """Generate sample data for a data source.
31
31
 
32
32
  Args:
33
33
  datasource: Path to the datasource file to load sample data into
@@ -23,7 +23,7 @@ from tinybird.tb.modules.feedback_manager import FeedbackManager
23
23
  @cli.group(hidden=False)
24
24
  @click.pass_context
25
25
  def pipe(ctx):
26
- """Pipe commands"""
26
+ """Pipe commands."""
27
27
 
28
28
 
29
29
  @pipe.command(name="ls")
@@ -0,0 +1,135 @@
1
+ import asyncio
2
+ import threading
3
+ import time
4
+ from copy import deepcopy
5
+ from pathlib import Path
6
+ from typing import List
7
+ from urllib.parse import urlencode
8
+
9
+ import click
10
+
11
+ import tinybird.context as context
12
+ from tinybird.client import TinyB
13
+ from tinybird.tb.modules.cli import cli
14
+ from tinybird.tb.modules.config import CLIConfig
15
+ from tinybird.tb.modules.datafile.exceptions import ParseException
16
+ from tinybird.tb.modules.datafile.parse_datasource import parse_datasource
17
+ from tinybird.tb.modules.datafile.parse_pipe import parse_pipe
18
+ from tinybird.tb.modules.datafile.playground import folder_playground
19
+ from tinybird.tb.modules.feedback_manager import FeedbackManager
20
+ from tinybird.tb.modules.project import Project
21
+ from tinybird.tb.modules.shell import Shell, print_table_formatted
22
+ from tinybird.tb.modules.watch import watch_files
23
+
24
+
25
+ def is_vendor(f: Path) -> bool:
26
+ return f.parts[0] == "vendor"
27
+
28
+
29
+ def get_vendor_workspace(f: Path) -> str:
30
+ return f.parts[1]
31
+
32
+
33
+ def is_endpoint(f: Path) -> bool:
34
+ return f.suffix == ".pipe" and not is_vendor(f) and f.parts[0] == "endpoints"
35
+
36
+
37
+ def is_pipe(f: Path) -> bool:
38
+ return f.suffix == ".pipe" and not is_vendor(f)
39
+
40
+
41
+ def check_filenames(filenames: List[str]):
42
+ parser_matrix = {".pipe": parse_pipe, ".datasource": parse_datasource}
43
+ incl_suffix = ".incl"
44
+
45
+ for filename in filenames:
46
+ file_suffix = Path(filename).suffix
47
+ if file_suffix == incl_suffix:
48
+ continue
49
+
50
+ parser = parser_matrix.get(file_suffix)
51
+ if not parser:
52
+ raise ParseException(FeedbackManager.error_unsupported_datafile(extension=file_suffix))
53
+
54
+ parser(filename)
55
+
56
+
57
+ @cli.command()
58
+ @click.pass_context
59
+ def playground(
60
+ ctx: click.Context,
61
+ ) -> None:
62
+ """Build the project in Tinybird Local."""
63
+ project: Project = ctx.ensure_object(dict)["project"]
64
+ tb_client: TinyB = ctx.ensure_object(dict)["client"]
65
+ context.disable_template_security_validation.set(True)
66
+
67
+ async def process(filenames: List[str], watch: bool = False):
68
+ datafiles = [f for f in filenames if f.endswith(".datasource") or f.endswith(".pipe")]
69
+ if len(datafiles) > 0:
70
+ check_filenames(filenames=datafiles)
71
+ await folder_playground(
72
+ project, tb_client, filenames=datafiles, is_internal=False, current_ws=None, local_ws=None
73
+ )
74
+ if len(filenames) > 0 and watch:
75
+ filename = filenames[0]
76
+ await build_and_print_resource(tb_client, filename)
77
+
78
+ datafiles = project.get_project_files()
79
+ filenames = datafiles
80
+
81
+ async def build_once(filenames: List[str]):
82
+ ok = False
83
+ try:
84
+ click.echo(FeedbackManager.highlight(message="» Building project...\n"))
85
+ time_start = time.time()
86
+ await process(filenames=filenames, watch=False)
87
+ time_end = time.time()
88
+ elapsed_time = time_end - time_start
89
+
90
+ click.echo(FeedbackManager.success(message=f"\n✓ Build completed in {elapsed_time:.1f}s"))
91
+ ok = True
92
+ except Exception as e:
93
+ error_path = Path(".tb_error.txt")
94
+ if error_path.exists():
95
+ content = error_path.read_text()
96
+ content += f"\n\n{str(e)}"
97
+ error_path.write_text(content)
98
+ else:
99
+ error_path.write_text(str(e))
100
+ click.echo(FeedbackManager.error_exception(error=e))
101
+ ok = False
102
+ return ok
103
+
104
+ build_ok = asyncio.run(build_once(filenames))
105
+
106
+ shell = Shell(project=project, tb_client=tb_client, playground=True)
107
+ click.echo(FeedbackManager.gray(message="\nWatching for changes..."))
108
+ watcher_thread = threading.Thread(
109
+ target=watch_files, args=(filenames, process, shell, project, build_ok), daemon=True
110
+ )
111
+ watcher_thread.start()
112
+ shell.run()
113
+
114
+
115
+ async def build_and_print_resource(tb_client: TinyB, filename: str):
116
+ resource_path = Path(filename)
117
+ name = resource_path.stem
118
+ playground_name = name if filename.endswith(".pipe") else None
119
+ config = CLIConfig().get_project_config()
120
+ user_client = deepcopy(tb_client)
121
+ user_client.token = config.get_user_token() or ""
122
+ cli_params = {}
123
+ cli_params["workspace_id"] = config.get("id", None)
124
+ data = await user_client._req(f"/v0/playgrounds?{urlencode(cli_params)}")
125
+ playgrounds = data["playgrounds"]
126
+ playground = next((p for p in playgrounds if p["name"] == (f"{playground_name}" + "__tb__playground")), None)
127
+ if not playground:
128
+ return
129
+ playground_id = playground["id"]
130
+ last_node = playground["nodes"][-1]
131
+ if not last_node:
132
+ return
133
+ node_sql = last_node["sql"]
134
+ res = await tb_client.query(f"{node_sql} FORMAT JSON", playground=playground_id)
135
+ print_table_formatted(res, name)
@@ -1,5 +1,6 @@
1
1
  import glob
2
2
  import os
3
+ import re
3
4
  from pathlib import Path
4
5
  from typing import Dict, List, Optional
5
6
 
@@ -78,3 +79,7 @@ class Project:
78
79
  if datafile := self.get_datafile(filename):
79
80
  datafiles[filename] = datafile
80
81
  return datafiles
82
+
83
+ @staticmethod
84
+ def is_endpoint(content: str) -> bool:
85
+ return re.search(r"TYPE endpoint", content, re.IGNORECASE) is not None
@@ -194,11 +194,12 @@ def _(event):
194
194
 
195
195
 
196
196
  class Shell:
197
- def __init__(self, project: Project, tb_client: TinyB):
197
+ def __init__(self, project: Project, tb_client: TinyB, playground: bool = False):
198
198
  self.history = self.get_history()
199
199
  self.project = project
200
200
  self.tb_client = tb_client
201
- self.prompt_message = "\ntb > "
201
+ self.env = "cloud" if playground else "build"
202
+ self.prompt_message = "\ntb » "
202
203
  self.session: PromptSession = PromptSession(
203
204
  completer=DynamicCompleter(project),
204
205
  complete_style=CompleteStyle.COLUMN,
@@ -266,7 +267,7 @@ class Shell:
266
267
  def handle_mock(self, arg):
267
268
  if "mock" in arg.strip().lower():
268
269
  arg = arg.replace("mock", "")
269
- subprocess.run(f"tb --build mock {arg}", shell=True, text=True)
270
+ subprocess.run(f"tb --{self.env} mock {arg}", shell=True, text=True)
270
271
 
271
272
  def handle_tb(self, argline):
272
273
  click.echo("")
@@ -283,7 +284,7 @@ class Shell:
283
284
  need_skip = ("mock", "test create", "create")
284
285
  if any(arg.startswith(cmd) for cmd in need_skip):
285
286
  argline = f"{argline}"
286
- subprocess.run(f"tb --build {argline}", shell=True, text=True)
287
+ subprocess.run(f"tb --{self.env} {argline}", shell=True, text=True)
287
288
 
288
289
  def default(self, argline):
289
290
  click.echo("")
@@ -298,7 +299,7 @@ class Shell:
298
299
  need_skip = ("mock", "test create", "create")
299
300
  if any(arg.startswith(cmd) for cmd in need_skip):
300
301
  argline = f"{argline}"
301
- subprocess.run(f"tb --build {argline}", shell=True, text=True)
302
+ subprocess.run(f"tb --{self.env} {argline}", shell=True, text=True)
302
303
 
303
304
  def run_sql(self, query, rows_limit=20):
304
305
  try:
@@ -17,7 +17,7 @@ from tinybird.tb.modules.exceptions import CLITokenException
17
17
  from tinybird.tb.modules.feedback_manager import FeedbackManager
18
18
 
19
19
 
20
- @cli.group(hidden=True)
20
+ @cli.group()
21
21
  @click.pass_context
22
22
  def token(ctx: Context) -> None:
23
23
  """Token commands."""
@@ -341,10 +341,24 @@ async def create_static_token(ctx, name: str):
341
341
  raise CLITokenException("Unknown error")
342
342
 
343
343
  try:
344
- await client.create_token(name, scoped_parsed, origin_code=None)
344
+ token = None
345
+ try:
346
+ click.echo(FeedbackManager.highlight(message=f"\n» Checking if token '{name}' exists..."))
347
+ token = await client.token_get(name)
348
+ except Exception:
349
+ pass
350
+ if token:
351
+ click.echo(FeedbackManager.info(message=f"* Token '{name}' found, updating it..."))
352
+ await client.alter_tokens(name, scoped_parsed)
353
+ else:
354
+ click.echo(FeedbackManager.info(message=f"* Token '{name}' not found, creating it..."))
355
+ await client.create_token(name, scoped_parsed, origin_code=None)
345
356
  except AuthNoTokenException:
346
357
  raise
347
358
  except Exception as e:
348
359
  raise CLITokenException(FeedbackManager.error_exception(error=e))
349
360
 
350
- click.echo("Token has been generated successfully.")
361
+ if token:
362
+ click.echo(FeedbackManager.success(message=f"✓ Token '{name}' updated successfully"))
363
+ else:
364
+ click.echo(FeedbackManager.success(message=f"✓ Token '{name}' generated successfully"))
@@ -1,12 +1,15 @@
1
+ import asyncio
1
2
  import os
2
3
  import time
3
4
  from pathlib import Path
4
- from typing import Any, Callable, Optional, Union
5
+ from typing import Any, Callable, List, Optional, Union
5
6
 
6
7
  import click
7
8
  from watchdog.events import (
8
9
  DirDeletedEvent,
10
+ DirMovedEvent,
9
11
  FileDeletedEvent,
12
+ FileMovedEvent,
10
13
  FileSystemEventHandler,
11
14
  )
12
15
  from watchdog.observers import Observer
@@ -136,3 +139,104 @@ def watch_project(
136
139
  observer.stop()
137
140
 
138
141
  observer.join()
142
+
143
+
144
+ class FileChangeHandler(FileSystemEventHandler):
145
+ def __init__(self, filenames: List[str], process: Callable[[List[str]], None], build_ok: bool):
146
+ self.unprocessed_filenames = [os.path.abspath(f) for f in filenames]
147
+ self.process = process
148
+ self.build_ok = build_ok
149
+
150
+ @property
151
+ def filenames(self) -> List[str]:
152
+ return [f for f in self.unprocessed_filenames if os.path.exists(f)]
153
+
154
+ def should_process(self, event: Any) -> Optional[str]:
155
+ if event.is_directory:
156
+ return None
157
+
158
+ def should_process_path(path: str) -> bool:
159
+ if not os.path.exists(path):
160
+ return False
161
+ is_vendor = "vendor/" in path
162
+ if is_vendor:
163
+ return False
164
+ return any(path.endswith(ext) for ext in [".datasource", ".pipe", ".ndjson"])
165
+
166
+ if should_process_path(event.src_path):
167
+ return event.src_path
168
+
169
+ if should_process_path(event.dest_path):
170
+ return event.dest_path
171
+
172
+ return None
173
+
174
+ def on_modified(self, event: Any) -> None:
175
+ if path := self.should_process(event):
176
+ filename = path.split("/")[-1]
177
+ click.echo(FeedbackManager.highlight(message=f"\n\n⟲ Changes detected in {filename}\n"))
178
+ try:
179
+ to_process = [path] if self.build_ok else self.filenames
180
+ self.process(to_process)
181
+ self.build_ok = True
182
+ except Exception as e:
183
+ click.echo(FeedbackManager.error_exception(error=e))
184
+
185
+ def on_moved(self, event: Union[DirMovedEvent, FileMovedEvent]) -> None:
186
+ if path := self.should_process(event):
187
+ is_new_file = False
188
+ if path not in self.unprocessed_filenames:
189
+ is_new_file = True
190
+ self.unprocessed_filenames.append(path)
191
+
192
+ filename = path.split("/")[-1]
193
+ if is_new_file:
194
+ click.echo(FeedbackManager.highlight(message=f"\n\n⟲ New file detected: {filename}\n"))
195
+ else:
196
+ click.echo(FeedbackManager.highlight(message=f"\n\n⟲ Changes detected in {filename}\n"))
197
+ try:
198
+ should_rebuild_all = is_new_file or not self.build_ok
199
+ to_process = self.filenames if should_rebuild_all else [path]
200
+ self.process(to_process)
201
+ self.build_ok = True
202
+ except Exception as e:
203
+ click.echo(FeedbackManager.error_exception(error=e))
204
+
205
+
206
+ def watch_files(
207
+ filenames: List[str],
208
+ process: Callable,
209
+ shell: Shell,
210
+ project: Project,
211
+ build_ok: bool,
212
+ ) -> None:
213
+ # Handle both sync and async process functions
214
+ async def process_wrapper(files: List[str]) -> None:
215
+ click.echo(FeedbackManager.highlight(message="» Rebuilding project..."))
216
+ time_start = time.time()
217
+ if asyncio.iscoroutinefunction(process):
218
+ await process(files, watch=True)
219
+ else:
220
+ process(files, watch=True)
221
+ time_end = time.time()
222
+ elapsed_time = time_end - time_start
223
+ click.echo(
224
+ FeedbackManager.success(message="\n✓ ")
225
+ + FeedbackManager.gray(message=f"Rebuild completed in {elapsed_time:.1f}s")
226
+ )
227
+ shell.reprint_prompt()
228
+
229
+ event_handler = FileChangeHandler(filenames, lambda f: asyncio.run(process_wrapper(f)), build_ok)
230
+ observer = Observer()
231
+
232
+ observer.schedule(event_handler, path=str(project.path), recursive=True)
233
+
234
+ observer.start()
235
+
236
+ try:
237
+ while True:
238
+ time.sleep(1)
239
+ except KeyboardInterrupt:
240
+ observer.stop()
241
+
242
+ observer.join()
@@ -32,7 +32,7 @@ from tinybird.tb.modules.feedback_manager import FeedbackManager
32
32
  @cli.group()
33
33
  @click.pass_context
34
34
  def workspace(ctx: Context) -> None:
35
- """Workspace commands"""
35
+ """Workspace commands."""
36
36
 
37
37
 
38
38
  @workspace.command(name="ls")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev72
3
+ Version: 0.0.1.dev74
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -1,12 +1,12 @@
1
1
  tinybird/__cli__.py,sha256=esPl5QDTzuQgHe5FuxWLm-fURFigGGwjnYLh9GuWUw4,232
2
- tinybird/client.py,sha256=7m2KL_K0e5pATOvkZTTZntjYEexsBd2G08-e1xVHGPk,52153
2
+ tinybird/client.py,sha256=EX2Z3AxZ9aG3c1qAFe1l48quiu19RfTV7TTuFelxjB4,52258
3
3
  tinybird/config.py,sha256=cd_RH7ZjqGjpWwu0efPkhS8VxD9K6Jix4QY2W3w1Pvs,5811
4
4
  tinybird/connectors.py,sha256=7Gjms7b5MAaBFGi3xytsJurCylprONpFcYrzp4Fw2Rc,15241
5
5
  tinybird/context.py,sha256=VaMhyHruH-uyMypPDfxtuo4scS18b7rxCCdeUVm6ysg,1301
6
6
  tinybird/datatypes.py,sha256=XNypumfqNjsvLJ5iNXnbVHRvAJe0aQwI3lS6Cxox-e0,10979
7
7
  tinybird/feedback_manager.py,sha256=Lsni8G80Qtv_KT_oUFJliQAg3zULFglyhUL27Q6U4cM,68005
8
8
  tinybird/git_settings.py,sha256=Sw_8rGmribEFJ4Z_6idrVytxpFYk7ez8ei0qHULzs3E,3934
9
- tinybird/prompts.py,sha256=kX-KTnto0Um0wL7Z5CM2VMCNjvGhuwzkMWpqCK9ymJI,30618
9
+ tinybird/prompts.py,sha256=rDIrkK5S1NJ0bIFjULsCYnGApv9Vc0jmR4tdRuJhM8c,32953
10
10
  tinybird/sql.py,sha256=LBi74GxhNAYTb6m2-KNGpAkguSKh7rcvBbERbE7nalA,46195
11
11
  tinybird/sql_template.py,sha256=hHz-EbHWlWVMS4e6hTpoieJ1qRAzzZLDq9-fnjT60dw,95732
12
12
  tinybird/sql_template_fmt.py,sha256=KUHdj5rYCYm_rKKdXYSJAE9vIyXUQLB0YSZnUXHeBlY,10196
@@ -15,47 +15,48 @@ tinybird/syncasync.py,sha256=IPnOx6lMbf9SNddN1eBtssg8vCLHMt76SuZ6YNYm-Yk,27761
15
15
  tinybird/tornado_template.py,sha256=KmW_VD7y-NVqrc8YZKwIaxoJB0XpCcB2izdmxmtmApM,41944
16
16
  tinybird/ch_utils/constants.py,sha256=aYvg2C_WxYWsnqPdZB1ZFoIr8ZY-XjUXYyHKE9Ansj0,3890
17
17
  tinybird/ch_utils/engine.py,sha256=AUAww-KjGOZg9h0IBlKA3FeacJYB4rOtqcTGJhFM-g8,40392
18
- tinybird/tb/__cli__.py,sha256=A34XRYM8ZbuXPkKJi3hAhztltcRfxP_aKhv4HkYHw9E,251
19
- tinybird/tb/cli.py,sha256=FD1pfbzu9YHJHEG6Vtn_EwPLTYhwqw-I6AxXeTaRHU8,926
18
+ tinybird/tb/__cli__.py,sha256=sa2SLi9xyvB-stMjO_bz2sJude-pMt2cBgZYff5bXh8,251
19
+ tinybird/tb/cli.py,sha256=KpJ_-V6xVEzcdPRPnHhEdh2EgRPCyhZnfJVqeqMsftI,964
20
20
  tinybird/tb/modules/auth.py,sha256=vBA-KsrjAp77kFunGSM-4o7AFdfO7ac4dnrHKrx0alI,9020
21
- tinybird/tb/modules/build.py,sha256=GIXpIAHxulB-PgJ2jeZnwIXPbL7anp3rPi5a6DxfWuQ,9674
21
+ tinybird/tb/modules/build.py,sha256=LBLyO5bVzqOegop459-V2QM1s48yMJu2GBSWBSio_u0,10323
22
22
  tinybird/tb/modules/cicd.py,sha256=Eyut5VsOtXq5hK9g_nGCJ2epfEMDDy2cX3kI0NPJZZA,5355
23
- tinybird/tb/modules/cli.py,sha256=jJuJUouENnxNZiaHrgMsqCcPFxNA2QtCunPWlcoyKbE,16300
24
- tinybird/tb/modules/common.py,sha256=AWjYgVXzJWqLAja3_d6T5y6e_zo1FOn0wrnlpXWaYhg,73222
25
- tinybird/tb/modules/config.py,sha256=iy6Nz7HKWksnArCdzuhw3ts-0NaFYEBEHtl8LVY9F30,11031
26
- tinybird/tb/modules/copy.py,sha256=Aq6wh_wjRiyLQtEOKF9pKLPgJhSvbGTFWIw_LJB0t0U,5801
23
+ tinybird/tb/modules/cli.py,sha256=zCVzffD3YIWB9y06SUf8Ir51R_mejLVTRnwi0SONNxk,16240
24
+ tinybird/tb/modules/common.py,sha256=f5yKjb1dgUzR-SrC4UHnpHXYIu6INcTHwNO96jW8A9w,73201
25
+ tinybird/tb/modules/config.py,sha256=mxUMLWnELkxgpWJAbAS6o0PXsL2fpG0ogdaZgr3xjvU,11038
26
+ tinybird/tb/modules/copy.py,sha256=MAVqKip8_QhOYq99U_XuqSO6hCLJEh5sFtbhcXtI3SI,5802
27
27
  tinybird/tb/modules/create.py,sha256=I01JDENOyGKK0Umd2_1Om_nFGP8Uk9vxaOw7PygK02o,12302
28
- tinybird/tb/modules/datasource.py,sha256=aOvjTVH9EdGNAw_lqhtZdJQhYnMOTGIqD3Pe4GtakFw,16905
29
- tinybird/tb/modules/deployment.py,sha256=LDFhUaC6QO7KVxtkaXOccRsksntrxladgGe-jMXlGFg,17407
30
- tinybird/tb/modules/endpoint.py,sha256=36TqACIJf27xWOKyBDuIReiHOD7xsFDjbv04wkp8bWI,12079
28
+ tinybird/tb/modules/datasource.py,sha256=dNCK9iCR2xPLfwqqwg2ixyE6NuoVEiJU2mBZBmOYrVY,16906
29
+ tinybird/tb/modules/deployment.py,sha256=umfWZA95WPRPUsJh8wSBj7Av_PevphWF6skJ1-lvnW8,16556
30
+ tinybird/tb/modules/endpoint.py,sha256=EhVoGAXsFz-83Fiwj1gI-I73iRRvL49d0W81un7hvPE,12080
31
31
  tinybird/tb/modules/exceptions.py,sha256=4A2sSjCEqKUMqpP3WI00zouCWW4uLaghXXLZBSw04mY,3363
32
32
  tinybird/tb/modules/feedback_manager.py,sha256=Lv5MBGWNbIFTIy4nNSi0c61bmiQRv5J0nHRiiXUqDuc,68478
33
- tinybird/tb/modules/fmt.py,sha256=j6W0X_h88oxfFppakJgZ8ubAUwwrCGsfVjKw4gg8e5s,3551
33
+ tinybird/tb/modules/fmt.py,sha256=qpf9APqKTKL2uphNgdbj4OMVyLkAxZn6dn4eHF99L5g,3553
34
34
  tinybird/tb/modules/job.py,sha256=956Pj8BEEsiD2GZsV9RKKVM3I_CveOLgS82lykO5ukk,2963
35
35
  tinybird/tb/modules/llm.py,sha256=AC0VSphTOM2t-v1_3NLvNN_FIbgMo4dTyMqIv5nniPo,835
36
36
  tinybird/tb/modules/llm_utils.py,sha256=nS9r4FAElJw8yXtmdYrx-rtI2zXR8qXfi1QqUDCfxvg,3469
37
- tinybird/tb/modules/local.py,sha256=_PIa-1M-72bv9rhLwqaNthJM1ZhvcjWXFChZAfEPXRs,5658
37
+ tinybird/tb/modules/local.py,sha256=9SZa-59eYROuwFNjJAHD0dRKLK5Reozh9WdchvfSsmQ,5680
38
38
  tinybird/tb/modules/local_common.py,sha256=K_RcB9Gay9xLZE_ZZmQs-fuoYHQ0hnZ4E5yTFMpbFoo,2910
39
39
  tinybird/tb/modules/login.py,sha256=EGxwVRmMX1Y7ZeCRyA8fqaCWpYYk7NvnZ3x_1g0NlYA,6063
40
- tinybird/tb/modules/materialization.py,sha256=dESybok66Fn7XLzQQr-fBCDNf5xQL8wkRiD2QBr5lOg,5748
41
- tinybird/tb/modules/mock.py,sha256=7alBqLfQLb7JSZJth9JDXGUOvABWXr8Gx23edgyrW8w,3869
42
- tinybird/tb/modules/pipe.py,sha256=PbCM31q9lVB9xPWvPBhlpW53MGFGvzVv81trxC06kDY,2428
43
- tinybird/tb/modules/project.py,sha256=QdOG65Hcc6r_eQ938CfZeIXyp38RkiTYNPupgqy2gP0,2948
40
+ tinybird/tb/modules/materialization.py,sha256=r8Q9HXcYEmfrEzP4WpiasCKDJdSkTPaAKJtZMoJKhi8,5749
41
+ tinybird/tb/modules/mock.py,sha256=ASJTm4p11vkevGXCvU0h57aw7Inx03CTdxd5o2uzd8k,3870
42
+ tinybird/tb/modules/pipe.py,sha256=gcLz0qHgwKDLsWFY3yFLO9a0ETAV1dFbI8YeLHi9460,2429
43
+ tinybird/tb/modules/playground.py,sha256=PKQKROen8sV7MaeMlxi2lIqZ8B14Sz2LgqjVMbBh0pk,4801
44
+ tinybird/tb/modules/project.py,sha256=YnrfDBenrzXCPO99qOtsTE21SP2vAb3FqBv6NV9Yw2g,3099
44
45
  tinybird/tb/modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
45
- tinybird/tb/modules/shell.py,sha256=qWpZ9TwDSDq3YsBxueNtezsslp3N7pwUPRF8HIlTjOo,13828
46
+ tinybird/tb/modules/shell.py,sha256=bhp5pOw4T_4p4XamWEoGJYRgrr5MREzZN8E36aYrb5U,13924
46
47
  tinybird/tb/modules/table.py,sha256=4XrtjM-N0zfNtxVkbvLDQQazno1EPXnxTyo7llivfXk,11035
47
48
  tinybird/tb/modules/tag.py,sha256=anPmMUBc-TbFovlpFi8GPkKA18y7Y0GczMsMms5TZsU,3502
48
49
  tinybird/tb/modules/telemetry.py,sha256=Hh2Io8ZPROSunbOLuMvuIFU4TqwWPmQTqal4WS09K1A,10449
49
50
  tinybird/tb/modules/test.py,sha256=4nB11SXv3HC33HaORdg1Erf5GXV2Teyedgs9u750qfM,11543
50
- tinybird/tb/modules/token.py,sha256=WEB2xqRgOierJ_S7TrZLEpLpQ9mkXcYLH2-xipjoGDc,12814
51
- tinybird/tb/modules/watch.py,sha256=IIahyfmVNNu_EY2dVKZ_zjdSEFocwsmpvvgki4EmU-w,4961
52
- tinybird/tb/modules/workspace.py,sha256=7gOgt10j9emleqQ43BA6jU0CZjJxw7L5gDZhCxGafI4,6400
51
+ tinybird/tb/modules/token.py,sha256=OhqLFpCHVfYeBCxJ0n7n2qoho9E9eGcUfHgL7R1MUVQ,13485
52
+ tinybird/tb/modules/watch.py,sha256=ldB29Y_v1amXcYWhh2hhhV3tekPioXQ7noEhPZhW2Ok,8670
53
+ tinybird/tb/modules/workspace.py,sha256=fF0W6M5_qdwbbXpCUfuhon7CR0NhOOA0XOv5jD2l1JI,6401
53
54
  tinybird/tb/modules/workspace_members.py,sha256=Vb5XEaKmkfONyfg2MS5EcpwolMvv7GLwFS5m2EuobT8,8726
54
55
  tinybird/tb/modules/datafile/build.py,sha256=seGFSvmgyRrAM1-icsKBkuog3WccfGUYFTPT-xoA5W8,50940
55
56
  tinybird/tb/modules/datafile/build_common.py,sha256=rT7VJ5mnQ68R_8US91DAtkusfvjWuG_NObOzNgtN_ko,4562
56
57
  tinybird/tb/modules/datafile/build_datasource.py,sha256=VjxaKKLZhPYt3XHOyMmfoqEAWAPI5D78T-8FOaN77MY,17355
57
- tinybird/tb/modules/datafile/build_pipe.py,sha256=Jgv3YKIvMfjPiSIdw1k2mpaoDdAWMiMRaSHwRgyI97E,28258
58
- tinybird/tb/modules/datafile/common.py,sha256=1sKkQnyKOaFARQzORncpL6cRVpV9GDOD4oC36daX-Hk,79343
58
+ tinybird/tb/modules/datafile/build_pipe.py,sha256=-22_657DiZodJ7shSu7KvwE_m6bHesNITdUgCMniuBI,22202
59
+ tinybird/tb/modules/datafile/common.py,sha256=dEGwdfJf90XQNh2FOLbAy-Y04X3RpfpafT8wzVU13aA,80088
59
60
  tinybird/tb/modules/datafile/diff.py,sha256=-0J7PsBO64T7LOZSkZ4ZFHHCPvT7cKItnJkbz2PkndU,6754
60
61
  tinybird/tb/modules/datafile/exceptions.py,sha256=8rw2umdZjtby85QbuRKFO5ETz_eRHwUY5l7eHsy1wnI,556
61
62
  tinybird/tb/modules/datafile/fixture.py,sha256=si-9LB-LdKQSWDtVW82xDrHtFfko5bgBG1cvjqqrcPU,1064
@@ -65,6 +66,7 @@ tinybird/tb/modules/datafile/format_pipe.py,sha256=58iSTrJ5lg-IsbpX8TQumQTuZ6UIo
65
66
  tinybird/tb/modules/datafile/parse_datasource.py,sha256=kk35PzesoJOd0LKjYp4kOyCwq4Qo4TiZnoI9qcXjB4k,1519
66
67
  tinybird/tb/modules/datafile/parse_pipe.py,sha256=snoy8Ac_Sat7LIXLAKzxjJSl2-TKg9FaZTooxrx6muE,3420
67
68
  tinybird/tb/modules/datafile/pipe_checker.py,sha256=LnDLGIHLJ3N7qHb2ptEbPr8CoczNfGwpjOY8EMdxfHQ,24649
69
+ tinybird/tb/modules/datafile/playground.py,sha256=0qNdVEiNRBvJVKL4url_tp6hVtAAdTxYqpLvyJs-loY,56382
68
70
  tinybird/tb/modules/datafile/pull.py,sha256=vcjMUbjnZ9XQMGmL33J3ElpbXBTat8Yzp-haeDggZd4,5967
69
71
  tinybird/tb/modules/tinyunit/tinyunit.py,sha256=GlDgEXc6TDO3ODxgfATAL2fvbKy-b_CzqoeDrApRm0g,11715
70
72
  tinybird/tb/modules/tinyunit/tinyunit_lib.py,sha256=hGh1ZaXC1af7rKnX7222urkj0QJMhMWclqMy59dOqwE,1922
@@ -74,8 +76,8 @@ tinybird/tb_cli_modules/config.py,sha256=6u6B5QCdiQLbJkCkwtnKGs9H3nP-KXXhC75mF7B
74
76
  tinybird/tb_cli_modules/exceptions.py,sha256=pmucP4kTF4irIt7dXiG-FcnI-o3mvDusPmch1L8RCWk,3367
75
77
  tinybird/tb_cli_modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
76
78
  tinybird/tb_cli_modules/telemetry.py,sha256=Hh2Io8ZPROSunbOLuMvuIFU4TqwWPmQTqal4WS09K1A,10449
77
- tinybird-0.0.1.dev72.dist-info/METADATA,sha256=Cap9mT7R-vptOxgQ7VVEKtucgxdpFUzYUfv9HSTR30c,2585
78
- tinybird-0.0.1.dev72.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
79
- tinybird-0.0.1.dev72.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
80
- tinybird-0.0.1.dev72.dist-info/top_level.txt,sha256=VqqqEmkAy7UNaD8-V51FCoMMWXjLUlR0IstvK7tJYVY,54
81
- tinybird-0.0.1.dev72.dist-info/RECORD,,
79
+ tinybird-0.0.1.dev74.dist-info/METADATA,sha256=1BtfBdQkgTyFzBZ6W4eL38o3T_02rjevCVjj7I6CCVE,2585
80
+ tinybird-0.0.1.dev74.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
81
+ tinybird-0.0.1.dev74.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
82
+ tinybird-0.0.1.dev74.dist-info/top_level.txt,sha256=VqqqEmkAy7UNaD8-V51FCoMMWXjLUlR0IstvK7tJYVY,54
83
+ tinybird-0.0.1.dev74.dist-info/RECORD,,