tinybird 0.0.1.dev18__py3-none-any.whl → 0.0.1.dev19__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.

tinybird/client.py CHANGED
@@ -103,7 +103,7 @@ class TinyB:
103
103
  self.send_telemetry = send_telemetry
104
104
  self.semver = semver
105
105
 
106
- async def _req(
106
+ async def _req_raw(
107
107
  self,
108
108
  endpoint: str,
109
109
  data=None,
@@ -155,10 +155,15 @@ class TinyB:
155
155
  response = await sync_to_async(session.get, thread_sensitive=False)(
156
156
  url, verify=verify_ssl, **kwargs
157
157
  )
158
-
159
158
  except Exception as e:
160
159
  raise e
161
160
 
161
+ if self.send_telemetry:
162
+ try:
163
+ add_telemetry_event("api_request", endpoint=url, token=self.token, status_code=response.status_code)
164
+ except Exception as ex:
165
+ logging.exception(f"Can't send telemetry: {ex}")
166
+
162
167
  logging.debug("== server response ==")
163
168
  logging.debug(response.content)
164
169
  logging.debug("== end ==")
@@ -169,6 +174,21 @@ class TinyB:
169
174
  except Exception as ex:
170
175
  logging.exception(f"Can't send telemetry: {ex}")
171
176
 
177
+ return response
178
+
179
+ async def _req(
180
+ self,
181
+ endpoint: str,
182
+ data=None,
183
+ files=None,
184
+ method: str = "GET",
185
+ retries: int = LIMIT_RETRIES,
186
+ use_token: Optional[str] = None,
187
+ **kwargs,
188
+ ):
189
+ token_to_use = use_token if use_token else self.token
190
+ response = await self._req_raw(endpoint, data, files, method, retries, use_token, **kwargs)
191
+
172
192
  if response.status_code == 403:
173
193
  error = parse_error_response(response)
174
194
  if not token_to_use:
tinybird/tb/__cli__.py ADDED
@@ -0,0 +1,8 @@
1
+
2
+ __name__ = 'tinybird'
3
+ __description__ = 'Tinybird Command Line Tool'
4
+ __url__ = 'https://www.tinybird.co/docs/cli/introduction.html'
5
+ __author__ = 'Tinybird'
6
+ __author_email__ = 'support@tinybird.co'
7
+ __version__ = '0.0.1.dev19'
8
+ __revision__ = '5ef65e7'
@@ -193,16 +193,30 @@ def build(
193
193
  paths = [Path(f) for f in get_project_filenames(folder, with_vendor=True)]
194
194
 
195
195
  def is_vendor(f: Path) -> bool:
196
- return "vendor/" in f.parts
196
+ return f.parts[0] == "vendor"
197
197
 
198
198
  def get_vendor_workspace(f: Path) -> str:
199
199
  return f.parts[1]
200
200
 
201
+ def is_endpoint(f: Path) -> bool:
202
+ return f.suffix == ".pipe" and not is_vendor(f) and f.parts[0] == "endpoints"
203
+
204
+ def is_pipe(f: Path) -> bool:
205
+ return f.suffix == ".pipe" and not is_vendor(f)
206
+
201
207
  datasource_paths = [f for f in paths if f.suffix == ".datasource"]
202
208
  datasources = [f.stem for f in datasource_paths if not is_vendor(f)]
203
209
  shared_datasources = [f"{get_vendor_workspace(f)}.{f.stem}" for f in datasource_paths if is_vendor(f)]
204
- pipes = [f.stem for f in paths if f.suffix == ".pipe" and not is_vendor(f)]
205
- shell = BuildShell(folder=folder, client=tb_client, datasources=datasources + shared_datasources, pipes=pipes)
210
+ pipes = [f.stem for f in paths if is_pipe(f) and not is_endpoint(f)]
211
+ endpoints = [f.stem for f in paths if is_endpoint(f)]
212
+ shell = BuildShell(
213
+ folder=folder,
214
+ client=tb_client,
215
+ datasources=datasources,
216
+ shared_datasources=shared_datasources,
217
+ pipes=pipes,
218
+ endpoints=endpoints,
219
+ )
206
220
  click.echo(FeedbackManager.highlight(message="◎ Watching for changes..."))
207
221
  watcher_thread = threading.Thread(
208
222
  target=watch_files, args=(filenames, process, shell, folder, build_ok), daemon=True
@@ -22,10 +22,13 @@ from tinybird.tb.modules.table import format_table
22
22
 
23
23
 
24
24
  class DynamicCompleter(Completer):
25
- def __init__(self, datasources: List[str], pipes: List[str]):
25
+ def __init__(self, datasources: List[str], shared_datasources: List[str], endpoints: List[str], pipes: List[str]):
26
26
  self.datasources = datasources
27
+ self.shared_datasources = shared_datasources
28
+ self.endpoints = endpoints
27
29
  self.pipes = pipes
28
30
  self.static_commands = ["create", "mock", "test", "select"]
31
+ self.test_commands = ["create", "run", "update"]
29
32
  self.mock_flags = ["--prompt", "--rows"]
30
33
  self.common_rows = ["10", "50", "100", "500", "1000"]
31
34
  self.sql_keywords = ["select", "from", "where", "group by", "order by", "limit"]
@@ -47,6 +50,8 @@ class DynamicCompleter(Completer):
47
50
 
48
51
  if command == "mock":
49
52
  yield from self._handle_mock_completions(words)
53
+ elif command == "test":
54
+ yield from self._handle_test_completions(words)
50
55
  elif command == "select" or self._is_sql_query(text.lower()):
51
56
  yield from self._handle_sql_completions(text)
52
57
  else:
@@ -71,9 +76,9 @@ class DynamicCompleter(Completer):
71
76
  if words[-1] == "from" or (
72
77
  "from" in words and len(words) > words.index("from") + 1 and text_lower.endswith(" ")
73
78
  ):
74
- for x in self.datasources:
79
+ for x in self.datasources + self.shared_datasources:
75
80
  yield Completion(x, start_position=0, display=x, style="class:completion.datasource")
76
- for x in self.pipes:
81
+ for x in self.endpoints + self.pipes:
77
82
  yield Completion(x, start_position=0, display=x, style="class:completion.pipe")
78
83
  return
79
84
 
@@ -89,22 +94,32 @@ class DynamicCompleter(Completer):
89
94
  if len(words) == 1:
90
95
  # After 'mock', show datasources
91
96
  for ds in self.datasources:
92
- yield Completion(ds, start_position=0, display=ds, style="class:completion.cmd")
97
+ yield Completion(ds, start_position=0, display=ds, style="class:completion.datasource")
93
98
  return
94
99
 
95
100
  if len(words) == 2 or len(words) == 4:
96
101
  # After datasource or after a flag value, show available flags
97
102
  available_flags = [f for f in self.mock_flags if f not in words]
98
103
  for flag in available_flags:
99
- yield Completion(flag, start_position=0, display=flag)
104
+ yield Completion(flag, start_position=0, display=flag, style="class:completion.cmd")
100
105
  return
101
106
 
102
107
  last_word = words[-1]
103
108
  if last_word == "--prompt":
104
- yield Completion('""', start_position=0, display='"Enter your prompt..."')
109
+ yield Completion('""', start_position=0, display='"Enter your prompt..."', style="class:completion.cmd")
105
110
  elif last_word == "--rows":
106
111
  for rows in self.common_rows:
107
- yield Completion(rows, start_position=0, display=rows)
112
+ yield Completion(rows, start_position=0, display=rows, style="class:completion.cmd")
113
+
114
+ def _handle_test_completions(self, words: List[str]):
115
+ if len(words) == 1:
116
+ for cmd in self.test_commands:
117
+ yield Completion(cmd, start_position=0, display=cmd, style="class:completion.cmd")
118
+ return
119
+ elif len(words) == 2:
120
+ for cmd in self.endpoints:
121
+ yield Completion(cmd, start_position=0, display=cmd, style="class:completion.pipe")
122
+ return
108
123
 
109
124
  def _yield_static_commands(self, current_word: str):
110
125
  for cmd in self.static_commands:
@@ -116,6 +131,24 @@ class DynamicCompleter(Completer):
116
131
  style="class:completion.cmd",
117
132
  )
118
133
 
134
+ for cmd in self.datasources + self.shared_datasources:
135
+ if cmd.startswith(current_word):
136
+ yield Completion(
137
+ cmd,
138
+ start_position=-len(current_word) if current_word else 0,
139
+ display=cmd,
140
+ style="class:completion.datasource",
141
+ )
142
+
143
+ for cmd in self.endpoints + self.pipes:
144
+ if cmd.startswith(current_word):
145
+ yield Completion(
146
+ cmd,
147
+ start_position=-len(current_word) if current_word else 0,
148
+ display=cmd,
149
+ style="class:completion.pipe",
150
+ )
151
+
119
152
 
120
153
  style = Style.from_dict(
121
154
  {
@@ -144,17 +177,27 @@ def _(event):
144
177
 
145
178
 
146
179
  class BuildShell:
147
- def __init__(self, folder: str, client: TinyB, datasources: List[str], pipes: List[str]):
180
+ def __init__(
181
+ self,
182
+ folder: str,
183
+ client: TinyB,
184
+ datasources: List[str],
185
+ shared_datasources: List[str],
186
+ pipes: List[str],
187
+ endpoints: List[str],
188
+ ):
148
189
  self.history = self.get_history()
149
190
  self.folder = folder
150
191
  self.client = client
151
192
  self.datasources = datasources
193
+ self.shared_datasources = shared_datasources
152
194
  self.pipes = pipes
195
+ self.endpoints = endpoints
153
196
  self.prompt_message = "\ntb > "
154
197
  self.commands = ["create", "mock", "test", "tb", "select"]
155
198
 
156
199
  self.session = PromptSession(
157
- completer=DynamicCompleter(self.datasources, self.pipes),
200
+ completer=DynamicCompleter(self.datasources, self.shared_datasources, self.endpoints, self.pipes),
158
201
  complete_style=CompleteStyle.COLUMN,
159
202
  complete_while_typing=True,
160
203
  history=self.history,
@@ -241,10 +284,9 @@ class BuildShell:
241
284
  if not arg:
242
285
  return
243
286
  if arg.startswith("with") or arg.startswith("select"):
244
- try:
245
- self.run_sql(argline)
246
- except Exception as e:
247
- click.echo(FeedbackManager.error(message=str(e)))
287
+ self.run_sql(argline)
288
+ elif len(arg.split()) == 1 and arg in self.endpoints + self.pipes + self.datasources + self.shared_datasources:
289
+ self.run_sql(f"select * from {arg}")
248
290
  else:
249
291
  subprocess.run(f"tb --local {arg}", shell=True, text=True)
250
292
 
@@ -271,10 +313,10 @@ class BuildShell:
271
313
  res = executor.submit(run_query_in_thread).result()
272
314
 
273
315
  except Exception as e:
274
- raise CLIException(FeedbackManager.error_exception(error=str(e)))
316
+ click.echo(FeedbackManager.error_exception(error=str(e)))
275
317
 
276
318
  if isinstance(res, dict) and "error" in res:
277
- raise CLIException(FeedbackManager.error_exception(error=res["error"]))
319
+ click.echo(FeedbackManager.error_exception(error=res["error"]))
278
320
 
279
321
  if isinstance(res, dict) and "data" in res and res["data"]:
280
322
  print_table_formatted(res, "QUERY")
@@ -26,8 +26,9 @@ from tinybird.client import (
26
26
  DoesNotExistException,
27
27
  TinyB,
28
28
  )
29
- from tinybird.config import SUPPORTED_CONNECTORS, VERSION, FeatureFlags, get_config
29
+ from tinybird.config import SUPPORTED_CONNECTORS, FeatureFlags, get_config
30
30
  from tinybird.feedback_manager import FeedbackManager
31
+ from tinybird.tb import __cli__
31
32
  from tinybird.tb.modules.common import (
32
33
  OLDEST_ROLLBACK,
33
34
  CatchAuthExceptions,
@@ -70,6 +71,7 @@ __old_click_secho = click.secho
70
71
  DEFAULT_PATTERNS: List[Tuple[str, Union[str, Callable[[str], str]]]] = [
71
72
  (r"p\.ey[A-Za-z0-9-_\.]+", lambda v: f"{v[:4]}...{v[-8:]}")
72
73
  ]
74
+ VERSION = f"{__cli__.__version__} (rev {__cli__.__revision__})"
73
75
 
74
76
 
75
77
  @click.group(cls=CatchAuthExceptions, context_settings={"help_option_names": ["-h", "--help"]})
@@ -1338,6 +1338,7 @@ def parse(
1338
1338
  "export_format": assign_var("export_format"),
1339
1339
  "export_strategy": assign_var("export_strategy"),
1340
1340
  "export_compression": assign_var("export_compression"),
1341
+ "export_write_strategy": assign_var("export_write_strategy"),
1341
1342
  "export_kafka_topic": assign_var("export_kafka_topic"),
1342
1343
  }
1343
1344
 
@@ -11,6 +11,7 @@ import requests
11
11
 
12
12
  from tinybird.feedback_manager import FeedbackManager
13
13
  from tinybird.tb.modules.cli import CLIConfig, cli
14
+ from tinybird.tb.modules.common import coro
14
15
 
15
16
 
16
17
  class AuthHandler(http.server.SimpleHTTPRequestHandler):
@@ -115,11 +116,11 @@ def start_server(auth_callback):
115
116
  "--workspace",
116
117
  help="Set the workspace to authenticate to. If not set, the default workspace will be used.",
117
118
  )
118
- def login(host: str, workspace: str):
119
+ @coro
120
+ async def login(host: str, workspace: str):
119
121
  """Authenticate via browser."""
120
122
  auth_event = threading.Event()
121
123
  auth_code = [None] # Using a list to store the code, as it's mutable
122
- config = CLIConfig.get_project_config()
123
124
  host = host or "https://api.tinybird.co"
124
125
 
125
126
  def auth_callback(code):
@@ -150,19 +151,25 @@ def login(host: str, workspace: str):
150
151
  params = {}
151
152
  if workspace:
152
153
  params["workspace_id"] = workspace
153
- response = requests.get(
154
+ response = requests.get( # noqa: ASYNC210
154
155
  f"{host}/v0/user/tokens?{urlencode(params)}",
155
156
  headers={"Authorization": f"Bearer {auth_code[0]}"},
156
157
  )
158
+
157
159
  data = response.json()
158
160
  cli_config = CLIConfig.get_project_config()
159
- workspace_token = data["workspace_token"]
160
- user_token = data["user_token"]
161
- cli_config.set_token(workspace_token)
162
- cli_config.set_token_for_host(workspace_token, host)
163
- cli_config.set_user_token(user_token)
164
- config.set_host(host)
161
+ cli_config.set_token(data["workspace_token"])
162
+ cli_config.set_token_for_host(data["workspace_token"], host)
163
+ cli_config.set_user_token(data["user_token"])
164
+ cli_config.set_host(host)
165
+
166
+ response = await cli_config.get_client().workspace_info()
167
+ for k in ("id", "name", "user_email", "user_id", "scope"):
168
+ if k in response:
169
+ cli_config[k] = response[k]
170
+
165
171
  cli_config.persist_to_file()
172
+
166
173
  click.echo(FeedbackManager.success(message="✓ Authentication successful!"))
167
174
  else:
168
175
  click.echo(FeedbackManager.error(message="Authentication failed or timed out."))
@@ -102,13 +102,21 @@ async def test_create(ctx: click.Context, pipe: str, prompt: Optional[str], fold
102
102
  test_params = (
103
103
  valid_test["parameters"] if valid_test["parameters"].startswith("?") else f"?{valid_test['parameters']}"
104
104
  )
105
- response = ""
105
+
106
+ response = None
106
107
  try:
107
- response = await client._req(f"/v0/pipes/{pipe_name}.ndjson{test_params}")
108
+ response = await client._req_raw(f"/v0/pipes/{pipe_name}.ndjson{test_params}")
108
109
  except Exception:
109
- valid_test["expected_http_status"] = 500
110
+ continue
111
+
112
+ if response.status_code >= 400:
113
+ valid_test["expected_http_status"] = response.status_code
114
+ valid_test["expected_result"] = response.json()["error"]
115
+ else:
116
+ if "expected_http_status" in valid_test:
117
+ del valid_test["expected_http_status"]
118
+ valid_test["expected_result"] = response.text or ""
110
119
 
111
- valid_test["expected_result"] = response
112
120
  valid_test_expectations.append(valid_test)
113
121
  if valid_test_expectations:
114
122
  generate_test_file(pipe_name, valid_test_expectations, folder, mode="a")
@@ -146,16 +154,20 @@ async def test_update(ctx: click.Context, pipe: str, folder: Optional[str]) -> N
146
154
  pipe_tests_content = yaml.safe_load(pipe_tests_path.read_text())
147
155
  for test in pipe_tests_content:
148
156
  test_params = test["parameters"] if test["parameters"].startswith("?") else f"?{test['parameters']}"
149
- response = ""
157
+ response = None
150
158
  try:
151
- response = await client._req(f"/v0/pipes/{pipe_name}.ndjson{test_params}")
159
+ response = await client._req_raw(f"/v0/pipes/{pipe_name}.ndjson{test_params}")
152
160
  except Exception:
153
- test["expected_http_status"] = 500
161
+ continue
162
+
163
+ if response.status_code >= 400:
164
+ test["expected_http_status"] = response.status_code
165
+ test["expected_result"] = response.json()["error"]
154
166
  else:
155
167
  if "expected_http_status" in test:
156
168
  del test["expected_http_status"]
157
169
 
158
- test["expected_result"] = response
170
+ test["expected_result"] = response.text or ""
159
171
 
160
172
  generate_test_file(pipe_name, pipe_tests_content, folder)
161
173
  click.echo(FeedbackManager.info(message=f"✓ /tests/{pipe_name}.yaml"))
@@ -166,18 +178,19 @@ async def test_update(ctx: click.Context, pipe: str, folder: Optional[str]) -> N
166
178
  name="run",
167
179
  help="Run the test suite, a file, or a test.",
168
180
  )
169
- @click.argument("file", nargs=-1)
181
+ @click.argument("name", nargs=-1)
170
182
  @click.option(
171
183
  "--folder",
172
184
  default=".",
173
185
  type=click.Path(exists=True, file_okay=False),
174
186
  help="Folder where tests will be placed",
175
187
  )
176
- @click.pass_context
177
188
  @coro
178
- async def test_run(ctx: click.Context, file: Tuple[str, ...], folder: Optional[str]) -> None:
189
+ async def test_run(name: Tuple[str, ...], folder: Optional[str]) -> None:
179
190
  client = await get_tinybird_local_client(os.path.abspath(folder))
180
- file_list: Iterable[str] = file if len(file) > 0 else glob.glob("./tests/**/*.y*ml", recursive=True)
191
+ paths = [Path(n) for n in name]
192
+ endpoints = [f"./tests/{p.stem}.yaml" for p in paths]
193
+ file_list: Iterable[str] = endpoints if len(endpoints) > 0 else glob.glob("./tests/**/*.y*ml", recursive=True)
181
194
 
182
195
  async def run_test(test_file):
183
196
  test_file_path = Path(test_file)
@@ -185,22 +198,28 @@ async def test_run(ctx: click.Context, file: Tuple[str, ...], folder: Optional[s
185
198
  for test in test_file_content:
186
199
  try:
187
200
  test_params = test["parameters"] if test["parameters"].startswith("?") else f"?{test['parameters']}"
188
- response = ""
201
+
202
+ response = None
189
203
  try:
190
- response = await client._req(f"/v0/pipes/{test_file_path.stem}.ndjson{test_params}")
204
+ response = await client._req_raw(f"/v0/pipes/{test_file_path.stem}.ndjson{test_params}")
191
205
  except Exception:
206
+ raise Exception("Expected to not fail but got an error")
207
+
208
+ expected_result = response.text
209
+ if response.status_code >= 400:
210
+ expected_result = response.json()["error"]
192
211
  if "expected_http_status" not in test:
193
212
  raise Exception("Expected to not fail but got an error")
194
- if test["expected_http_status"] != 500:
195
- raise Exception(f"Expected {test['expected_http_status']} but got another status")
213
+ if test["expected_http_status"] != response.status_code:
214
+ raise Exception(f"Expected {test['expected_http_status']} but got {response.status_code}")
196
215
 
197
- if test["expected_result"] != response:
216
+ if test["expected_result"] != expected_result:
198
217
  diff = difflib.ndiff(
199
- test["expected_result"].splitlines(keepends=True), response.splitlines(keepends=True)
218
+ test["expected_result"].splitlines(keepends=True), expected_result.splitlines(keepends=True)
200
219
  )
201
220
  printable_diff = "".join(diff)
202
221
  raise Exception(
203
- f"\nExpected: \n{test['expected_result']}\nGot: \n{response}\nDiff: \n{printable_diff}"
222
+ f"\nExpected: \n{test['expected_result']}\nGot: \n{expected_result}\nDiff: \n{printable_diff}"
204
223
  )
205
224
  click.echo(FeedbackManager.success(message=f"✓ {test_file_path.name} - {test['name']}"))
206
225
  except Exception as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tinybird
3
- Version: 0.0.1.dev18
3
+ Version: 0.0.1.dev19
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -1,5 +1,5 @@
1
1
  tinybird/__cli__.py,sha256=pgYsVLcqL16wtSn6KtKweNZYoYJdEksTgSvQAW7hH64,250
2
- tinybird/client.py,sha256=_voHMgKOwOhmncSaPH6DL94X6YPqKJJzcY-EKp8xLug,50810
2
+ tinybird/client.py,sha256=iPtpEhKB3alvo0o4kKMePrt1N7VbwtrKvH10OSWFAaA,51498
3
3
  tinybird/config.py,sha256=Z-BX9FrjgsLw1YwcCdF0IztLB97Zpc70VVPplO_pDSY,6089
4
4
  tinybird/connectors.py,sha256=lkpVSUmSuViEZBa4QjTK7YmPHUop0a5UFoTrSmlVq6k,15244
5
5
  tinybird/context.py,sha256=kutUQ0kCwparowI74_YLXx6wtTzGLRouJ6oGHVBPzBo,1291
@@ -15,12 +15,13 @@ tinybird/syncasync.py,sha256=fAvq0qkRgqXqXMKwbY2iJNYqLT_r6mDsh1MRpGKrdRU,27763
15
15
  tinybird/tornado_template.py,sha256=o2HguxrL1Evnt8o3IvrsI8Zm6JtRQ3zhLJKf1XyR3SQ,41965
16
16
  tinybird/ch_utils/constants.py,sha256=aYvg2C_WxYWsnqPdZB1ZFoIr8ZY-XjUXYyHKE9Ansj0,3890
17
17
  tinybird/ch_utils/engine.py,sha256=OXkBhlzGjZotjD0vaT-rFIbSGV4tpiHxE8qO_ip0SyQ,40454
18
+ tinybird/tb/__cli__.py,sha256=Rkdf_rWmJCmGhDIUL6WoCdXi5BDn2cZHjhBCqPvzpu8,251
18
19
  tinybird/tb/cli.py,sha256=onCxcKvTV4RuokC5V3t82OXWAIwgU6pMWs8rpWOUi_o,815
19
20
  tinybird/tb/modules/auth.py,sha256=hynZ-Temot8YBsySUWKSFzZlYadtFPxG3o6lCSu1n6E,9018
20
- tinybird/tb/modules/build.py,sha256=RILQAcx6Im8JSaL3ybJTOAm_oatuxdEfbVYl-5eAIgo,8998
21
- tinybird/tb/modules/build_shell.py,sha256=hmOlKl_rz3cG8z4pAybi2WnzuaD4NbCBU-IQ_zWrock,12254
21
+ tinybird/tb/modules/build.py,sha256=oVHv9kbim6ZhupLtCIxfgeZOCriqfH4Oz9S5Komv_9c,9409
22
+ tinybird/tb/modules/build_shell.py,sha256=3ec18FWyyF5lWgrf8F2n8-3ngQccJUmN2cwB9-_S_1g,14083
22
23
  tinybird/tb/modules/cicd.py,sha256=Xa3M7Egq4eDS6QIhrx8C8Ixf-R7oiZpO-5ZBPqYAKtI,5344
23
- tinybird/tb/modules/cli.py,sha256=PRURYKphzjqVltMG647D8ADGS-YFR2rAkDNEwUTTDjk,53082
24
+ tinybird/tb/modules/cli.py,sha256=hN5_DijZZ-E2OtLe0tgnu4a_5KCzY9EeOjE-bEJefos,53169
24
25
  tinybird/tb/modules/common.py,sha256=XfpzFVT9xJZ_HH7EZRLAjRMkTtz5rP7Njld5-EwMqiA,72400
25
26
  tinybird/tb/modules/config.py,sha256=ri4Gwyzqol6-NofTjHnWquuDzJOjHbkaAnboO8JNENY,11499
26
27
  tinybird/tb/modules/connection.py,sha256=ZSqBGoRiJedjHKEyB_fr1ybucOHtaad8d7uqGa2Q92M,28668
@@ -32,14 +33,14 @@ tinybird/tb/modules/job.py,sha256=eoBVyA24lYIPonU88Jn7FF9hBKz1kScy9_w_oWreuc4,29
32
33
  tinybird/tb/modules/llm.py,sha256=OcyRzQ0V392XsiGFwrrpjkCuV6AdE6cnhh6cDKPQt7U,3102
33
34
  tinybird/tb/modules/local.py,sha256=hV2fvHPaVHVzKwVoVDFAIbJZslOX1_COx96DZrR-dW8,5151
34
35
  tinybird/tb/modules/local_common.py,sha256=PsQu0Sg8BruusPzlzvs6dd2WlomvOcks-B37A798-Ls,2133
35
- tinybird/tb/modules/login.py,sha256=kx3I197rOaBzyBMNyFKUoLK7sGXD5NWURJFvUbU6lZc,5832
36
+ tinybird/tb/modules/login.py,sha256=ydyn64fbz3BOlSf5SZuIFvgsCpxQAQir8nJQSdMeq94,6011
36
37
  tinybird/tb/modules/mock.py,sha256=cpEmfSv5Osy_YF5eaFcAlpAYi0oVlX1NQH4mnAKvlUI,2884
37
38
  tinybird/tb/modules/pipe.py,sha256=P_W5HW1-UEidWlw0pty-n_qYvCAyMlNorBmWzmCP7cU,30906
38
39
  tinybird/tb/modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
39
40
  tinybird/tb/modules/table.py,sha256=hG-PRDVuFp2uph41WpoLRV1yjp3RI2fi_iGGiI0rdxU,7695
40
41
  tinybird/tb/modules/tag.py,sha256=1qQWyk1p3Btv3LzM8VbJG-k7x2-pFuAlYCg3QL6QewI,3480
41
42
  tinybird/tb/modules/telemetry.py,sha256=iEGnMuCuNhvF6ln__j6X9MSTwL_0Hm-GgFHHHvhfknk,10466
42
- tinybird/tb/modules/test.py,sha256=wvD3wDDAhvNyrFtsGXYfk45OuKY9Kix-1n8pzIhlhx4,8024
43
+ tinybird/tb/modules/test.py,sha256=Br0gXS9FrpFEnA6mnSm5fRbYnaw10AL_Z0gbaDfvDoM,8857
43
44
  tinybird/tb/modules/token.py,sha256=r0oeG1RpOOzHtqbUaHBiOmhE55HfNIvReAAWyKl9fJg,12695
44
45
  tinybird/tb/modules/workspace.py,sha256=FVlh-kbiZp5Gvp6dGFxi0UD8ail77rMamXLhqdVwrZ0,10916
45
46
  tinybird/tb/modules/workspace_members.py,sha256=08W0onEYkKLEC5TkAI07cxN9XSquEm7HnL7OkHAVDjo,8715
@@ -47,7 +48,7 @@ tinybird/tb/modules/datafile/build.py,sha256=rFdK_GerPDgPfyPfZ4EZ0-cQqWfHd6htS0l
47
48
  tinybird/tb/modules/datafile/build_common.py,sha256=74547h5ja4C66DAwDMabj75FA_BUTJxTJv-24tSFmrs,4551
48
49
  tinybird/tb/modules/datafile/build_datasource.py,sha256=fquzEGwk9NL_0K5YYG86Xtvgn4J5YHtRUoKJxbQGO0s,17344
49
50
  tinybird/tb/modules/datafile/build_pipe.py,sha256=V5u21NEpSCWNVl46Cdn_I_bOojxpgSrg1MnScPDqx4U,27648
50
- tinybird/tb/modules/datafile/common.py,sha256=NEX_fzDD1WGdo1oYMX8_w_M_wZQPvLAEOzGwC3Ph1mc,75632
51
+ tinybird/tb/modules/datafile/common.py,sha256=3CwspnffLUOlbfHMzjEvNebX--5sOC8DUKOC__3_fTA,75702
51
52
  tinybird/tb/modules/datafile/diff.py,sha256=-iaP7GvAzZtZSa8jPgVpOFlTRutxgxRBLBcGL1_RFr4,6743
52
53
  tinybird/tb/modules/datafile/exceptions.py,sha256=8rw2umdZjtby85QbuRKFO5ETz_eRHwUY5l7eHsy1wnI,556
53
54
  tinybird/tb/modules/datafile/fixture.py,sha256=YHlL4tojmPwm343Y8KO6r7d5Bhsk7U3lKP-oLMeBMsY,1771
@@ -66,8 +67,8 @@ tinybird/tb_cli_modules/config.py,sha256=6NTgIdwf0X132A1j6G_YrdPep87ymZ9b5pABabK
66
67
  tinybird/tb_cli_modules/exceptions.py,sha256=pmucP4kTF4irIt7dXiG-FcnI-o3mvDusPmch1L8RCWk,3367
67
68
  tinybird/tb_cli_modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
68
69
  tinybird/tb_cli_modules/telemetry.py,sha256=iEGnMuCuNhvF6ln__j6X9MSTwL_0Hm-GgFHHHvhfknk,10466
69
- tinybird-0.0.1.dev18.dist-info/METADATA,sha256=BXYeNyT3BS_18oePeU18RfW9Zbx0p6Rq_uPFRCN_Ss8,2446
70
- tinybird-0.0.1.dev18.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
71
- tinybird-0.0.1.dev18.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
72
- tinybird-0.0.1.dev18.dist-info/top_level.txt,sha256=pgw6AzERHBcW3YTi2PW4arjxLkulk2msOz_SomfOEuc,45
73
- tinybird-0.0.1.dev18.dist-info/RECORD,,
70
+ tinybird-0.0.1.dev19.dist-info/METADATA,sha256=AxNU0bAKXE2-n882WlwLmg8drAgVN4uLrnhCqGHhqxY,2446
71
+ tinybird-0.0.1.dev19.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
72
+ tinybird-0.0.1.dev19.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
73
+ tinybird-0.0.1.dev19.dist-info/top_level.txt,sha256=pgw6AzERHBcW3YTi2PW4arjxLkulk2msOz_SomfOEuc,45
74
+ tinybird-0.0.1.dev19.dist-info/RECORD,,