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 +22 -2
- tinybird/tb/__cli__.py +8 -0
- tinybird/tb/modules/build.py +17 -3
- tinybird/tb/modules/build_shell.py +57 -15
- tinybird/tb/modules/cli.py +3 -1
- tinybird/tb/modules/datafile/common.py +1 -0
- tinybird/tb/modules/login.py +16 -9
- tinybird/tb/modules/test.py +38 -19
- {tinybird-0.0.1.dev18.dist-info → tinybird-0.0.1.dev19.dist-info}/METADATA +1 -1
- {tinybird-0.0.1.dev18.dist-info → tinybird-0.0.1.dev19.dist-info}/RECORD +13 -12
- {tinybird-0.0.1.dev18.dist-info → tinybird-0.0.1.dev19.dist-info}/WHEEL +0 -0
- {tinybird-0.0.1.dev18.dist-info → tinybird-0.0.1.dev19.dist-info}/entry_points.txt +0 -0
- {tinybird-0.0.1.dev18.dist-info → tinybird-0.0.1.dev19.dist-info}/top_level.txt +0 -0
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
|
|
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
tinybird/tb/modules/build.py
CHANGED
|
@@ -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
|
|
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
|
|
205
|
-
|
|
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.
|
|
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__(
|
|
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
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
-
|
|
316
|
+
click.echo(FeedbackManager.error_exception(error=str(e)))
|
|
275
317
|
|
|
276
318
|
if isinstance(res, dict) and "error" in res:
|
|
277
|
-
|
|
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")
|
tinybird/tb/modules/cli.py
CHANGED
|
@@ -26,8 +26,9 @@ from tinybird.client import (
|
|
|
26
26
|
DoesNotExistException,
|
|
27
27
|
TinyB,
|
|
28
28
|
)
|
|
29
|
-
from tinybird.config import SUPPORTED_CONNECTORS,
|
|
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
|
|
tinybird/tb/modules/login.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
cli_config.
|
|
162
|
-
cli_config.
|
|
163
|
-
|
|
164
|
-
|
|
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."))
|
tinybird/tb/modules/test.py
CHANGED
|
@@ -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
|
-
|
|
105
|
+
|
|
106
|
+
response = None
|
|
106
107
|
try:
|
|
107
|
-
response = await client.
|
|
108
|
+
response = await client._req_raw(f"/v0/pipes/{pipe_name}.ndjson{test_params}")
|
|
108
109
|
except Exception:
|
|
109
|
-
|
|
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.
|
|
159
|
+
response = await client._req_raw(f"/v0/pipes/{pipe_name}.ndjson{test_params}")
|
|
152
160
|
except Exception:
|
|
153
|
-
|
|
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
|
-
|
|
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("
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
201
|
+
|
|
202
|
+
response = None
|
|
189
203
|
try:
|
|
190
|
-
response = await client.
|
|
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"] !=
|
|
195
|
-
raise Exception(f"Expected {test['expected_http_status']} but got
|
|
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"] !=
|
|
216
|
+
if test["expected_result"] != expected_result:
|
|
198
217
|
diff = difflib.ndiff(
|
|
199
|
-
test["expected_result"].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{
|
|
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,5 +1,5 @@
|
|
|
1
1
|
tinybird/__cli__.py,sha256=pgYsVLcqL16wtSn6KtKweNZYoYJdEksTgSvQAW7hH64,250
|
|
2
|
-
tinybird/client.py,sha256=
|
|
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=
|
|
21
|
-
tinybird/tb/modules/build_shell.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
70
|
-
tinybird-0.0.1.
|
|
71
|
-
tinybird-0.0.1.
|
|
72
|
-
tinybird-0.0.1.
|
|
73
|
-
tinybird-0.0.1.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|