tinybird-cli 6.4.2.dev0__py3-none-any.whl → 6.5.1.dev0__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.
- tinybird/__cli__.py +2 -2
- tinybird/client.py +43 -7
- tinybird/datafile_common.py +93 -36
- tinybird/datatypes.py +2 -2
- tinybird/sql_template.py +1 -1
- tinybird/sql_toolset.py +1 -1
- tinybird/tb_cli_modules/branch.py +4 -5
- tinybird/tb_cli_modules/cli.py +1 -3
- tinybird/tb_cli_modules/common.py +5 -3
- tinybird/tb_cli_modules/job.py +1 -3
- tinybird/tb_cli_modules/tag.py +2 -3
- tinybird/tb_cli_modules/workspace.py +10 -11
- {tinybird_cli-6.4.2.dev0.dist-info → tinybird_cli-6.5.1.dev0.dist-info}/METADATA +6 -1
- {tinybird_cli-6.4.2.dev0.dist-info → tinybird_cli-6.5.1.dev0.dist-info}/RECORD +17 -17
- {tinybird_cli-6.4.2.dev0.dist-info → tinybird_cli-6.5.1.dev0.dist-info}/WHEEL +0 -0
- {tinybird_cli-6.4.2.dev0.dist-info → tinybird_cli-6.5.1.dev0.dist-info}/entry_points.txt +0 -0
- {tinybird_cli-6.4.2.dev0.dist-info → tinybird_cli-6.5.1.dev0.dist-info}/top_level.txt +0 -0
tinybird/__cli__.py
CHANGED
|
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
|
|
|
4
4
|
__url__ = 'https://www.tinybird.co/docs/cli'
|
|
5
5
|
__author__ = 'Tinybird'
|
|
6
6
|
__author_email__ = 'support@tinybird.co'
|
|
7
|
-
__version__ = '6.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '6.5.1.dev0'
|
|
8
|
+
__revision__ = '676e19d'
|
tinybird/client.py
CHANGED
|
@@ -340,10 +340,14 @@ class TinyB:
|
|
|
340
340
|
for c in connectors
|
|
341
341
|
]
|
|
342
342
|
|
|
343
|
-
async def get_datasource(
|
|
343
|
+
async def get_datasource(
|
|
344
|
+
self, ds_name: str, used_by: bool = False, include_workspace_names: bool = False
|
|
345
|
+
) -> Dict[str, Any]:
|
|
344
346
|
params = {
|
|
345
347
|
"attrs": "used_by" if used_by else "",
|
|
346
348
|
}
|
|
349
|
+
if include_workspace_names:
|
|
350
|
+
params["include_workspace_names"] = "true"
|
|
347
351
|
return await self._req(f"/v0/datasources/{ds_name}?{urlencode(params)}")
|
|
348
352
|
|
|
349
353
|
async def alter_datasource(
|
|
@@ -489,12 +493,32 @@ class TinyB:
|
|
|
489
493
|
|
|
490
494
|
return await self._req(f"/v0/dependencies?{urlencode(params)}", timeout=60)
|
|
491
495
|
|
|
492
|
-
async def datasource_share(
|
|
493
|
-
|
|
496
|
+
async def datasource_share(
|
|
497
|
+
self,
|
|
498
|
+
datasource_id: str,
|
|
499
|
+
current_workspace_id: str,
|
|
500
|
+
destination_workspace_id: Optional[str] = None,
|
|
501
|
+
destination_workspace_name: Optional[str] = None,
|
|
502
|
+
) -> Dict[str, Any]:
|
|
503
|
+
params = {"origin_workspace_id": current_workspace_id}
|
|
504
|
+
if destination_workspace_id:
|
|
505
|
+
params["destination_workspace_id"] = destination_workspace_id
|
|
506
|
+
if destination_workspace_name:
|
|
507
|
+
params["destination_workspace_name"] = destination_workspace_name
|
|
494
508
|
return await self._req(f"/v0/datasources/{datasource_id}/share", method="POST", data=params)
|
|
495
509
|
|
|
496
|
-
async def datasource_unshare(
|
|
497
|
-
|
|
510
|
+
async def datasource_unshare(
|
|
511
|
+
self,
|
|
512
|
+
datasource_id: str,
|
|
513
|
+
current_workspace_id: str,
|
|
514
|
+
destination_workspace_id: Optional[str] = None,
|
|
515
|
+
destination_workspace_name: Optional[str] = None,
|
|
516
|
+
) -> Dict[str, Any]:
|
|
517
|
+
params = {"origin_workspace_id": current_workspace_id}
|
|
518
|
+
if destination_workspace_id:
|
|
519
|
+
params["destination_workspace_id"] = destination_workspace_id
|
|
520
|
+
if destination_workspace_name:
|
|
521
|
+
params["destination_workspace_name"] = destination_workspace_name
|
|
498
522
|
return await self._req(f"/v0/datasources/{datasource_id}/share", method="DELETE", data=params)
|
|
499
523
|
|
|
500
524
|
async def datasource_sync(self, datasource_id: str):
|
|
@@ -972,16 +996,28 @@ class TinyB:
|
|
|
972
996
|
kafka_sasl_mechanism="PLAIN",
|
|
973
997
|
kafka_security_protocol="SASL_SSL",
|
|
974
998
|
kafka_ssl_ca_pem=None,
|
|
999
|
+
kafka_sasl_oauthbearer_method=None,
|
|
1000
|
+
kafka_sasl_oauthbearer_aws_region=None,
|
|
1001
|
+
kafka_sasl_oauthbearer_aws_role_arn=None,
|
|
1002
|
+
kafka_sasl_oauthbearer_aws_external_id=None,
|
|
975
1003
|
):
|
|
1004
|
+
is_oauthbearer = kafka_sasl_mechanism == "OAUTHBEARER"
|
|
976
1005
|
params = {
|
|
977
1006
|
"service": "kafka",
|
|
978
1007
|
"kafka_security_protocol": kafka_security_protocol,
|
|
979
1008
|
"kafka_sasl_mechanism": kafka_sasl_mechanism,
|
|
980
1009
|
"kafka_bootstrap_servers": kafka_bootstrap_servers,
|
|
981
|
-
"kafka_sasl_plain_username": kafka_key,
|
|
982
|
-
"kafka_sasl_plain_password": kafka_secret,
|
|
983
1010
|
"name": kafka_connection_name,
|
|
984
1011
|
}
|
|
1012
|
+
if is_oauthbearer:
|
|
1013
|
+
params["kafka_sasl_oauthbearer_method"] = kafka_sasl_oauthbearer_method
|
|
1014
|
+
params["kafka_sasl_oauthbearer_aws_region"] = kafka_sasl_oauthbearer_aws_region
|
|
1015
|
+
params["kafka_sasl_oauthbearer_aws_role_arn"] = kafka_sasl_oauthbearer_aws_role_arn
|
|
1016
|
+
if kafka_sasl_oauthbearer_aws_external_id:
|
|
1017
|
+
params["kafka_sasl_oauthbearer_aws_external_id"] = kafka_sasl_oauthbearer_aws_external_id
|
|
1018
|
+
else:
|
|
1019
|
+
params["kafka_sasl_plain_username"] = kafka_key
|
|
1020
|
+
params["kafka_sasl_plain_password"] = kafka_secret
|
|
985
1021
|
|
|
986
1022
|
if kafka_schema_registry_url:
|
|
987
1023
|
params["kafka_schema_registry_url"] = kafka_schema_registry_url
|
tinybird/datafile_common.py
CHANGED
|
@@ -425,7 +425,7 @@ class CLIGitRelease:
|
|
|
425
425
|
|
|
426
426
|
def is_dirty_to_release(self, use_include_dir: bool = True) -> bool:
|
|
427
427
|
if use_include_dir:
|
|
428
|
-
return any(
|
|
428
|
+
return any(self.repo.is_dirty(path=p) for p in self.paths) or self.has_untracked_files()
|
|
429
429
|
else:
|
|
430
430
|
return self.repo.is_dirty(path=self.path) or self.has_untracked_files()
|
|
431
431
|
|
|
@@ -1235,6 +1235,10 @@ def parse(
|
|
|
1235
1235
|
"kafka_key_avro_deserialization": assign_var("kafka_key_avro_deserialization"),
|
|
1236
1236
|
"kafka_ssl_ca_pem": assign_var("kafka_ssl_ca_pem"),
|
|
1237
1237
|
"kafka_sasl_mechanism": assign_var("kafka_sasl_mechanism"),
|
|
1238
|
+
"kafka_sasl_oauthbearer_method": assign_var("kafka_sasl_oauthbearer_method"),
|
|
1239
|
+
"kafka_sasl_oauthbearer_aws_region": assign_var("kafka_sasl_oauthbearer_aws_region"),
|
|
1240
|
+
"kafka_sasl_oauthbearer_aws_role_arn": assign_var("kafka_sasl_oauthbearer_aws_role_arn"),
|
|
1241
|
+
"kafka_sasl_oauthbearer_aws_external_id": assign_var("kafka_sasl_oauthbearer_aws_external_id"),
|
|
1238
1242
|
"import_service": assign_var("import_service"),
|
|
1239
1243
|
"import_connection_name": assign_var("import_connection_name"),
|
|
1240
1244
|
"import_schedule": assign_var("import_schedule"),
|
|
@@ -1368,6 +1372,7 @@ async def process_file(
|
|
|
1368
1372
|
|
|
1369
1373
|
if not skip_connectors:
|
|
1370
1374
|
try:
|
|
1375
|
+
is_oauthbearer = params.get("kafka_sasl_mechanism") == "OAUTHBEARER"
|
|
1371
1376
|
connector_params = {
|
|
1372
1377
|
"kafka_bootstrap_servers": params.get("kafka_bootstrap_servers", None),
|
|
1373
1378
|
"kafka_key": params.get("kafka_key", None),
|
|
@@ -1377,6 +1382,12 @@ async def process_file(
|
|
|
1377
1382
|
"kafka_schema_registry_url": params.get("kafka_schema_registry_url", None),
|
|
1378
1383
|
"kafka_ssl_ca_pem": get_ca_pem_content(params.get("kafka_ssl_ca_pem", None), filename),
|
|
1379
1384
|
"kafka_sasl_mechanism": params.get("kafka_sasl_mechanism", None),
|
|
1385
|
+
"kafka_sasl_oauthbearer_method": params.get("kafka_sasl_oauthbearer_method", None),
|
|
1386
|
+
"kafka_sasl_oauthbearer_aws_region": params.get("kafka_sasl_oauthbearer_aws_region", None),
|
|
1387
|
+
"kafka_sasl_oauthbearer_aws_role_arn": params.get("kafka_sasl_oauthbearer_aws_role_arn", None),
|
|
1388
|
+
"kafka_sasl_oauthbearer_aws_external_id": params.get(
|
|
1389
|
+
"kafka_sasl_oauthbearer_aws_external_id", None
|
|
1390
|
+
),
|
|
1380
1391
|
}
|
|
1381
1392
|
|
|
1382
1393
|
connector = await tb_client.get_connection(**connector_params)
|
|
@@ -1384,11 +1395,19 @@ async def process_file(
|
|
|
1384
1395
|
click.echo(
|
|
1385
1396
|
FeedbackManager.info_creating_kafka_connection(connection_name=params["kafka_connection_name"])
|
|
1386
1397
|
)
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1398
|
+
if is_oauthbearer:
|
|
1399
|
+
required_params = [
|
|
1400
|
+
connector_params["kafka_bootstrap_servers"],
|
|
1401
|
+
connector_params["kafka_sasl_oauthbearer_method"],
|
|
1402
|
+
connector_params["kafka_sasl_oauthbearer_aws_region"],
|
|
1403
|
+
connector_params["kafka_sasl_oauthbearer_aws_role_arn"],
|
|
1404
|
+
]
|
|
1405
|
+
else:
|
|
1406
|
+
required_params = [
|
|
1407
|
+
connector_params["kafka_bootstrap_servers"],
|
|
1408
|
+
connector_params["kafka_key"],
|
|
1409
|
+
connector_params["kafka_secret"],
|
|
1410
|
+
]
|
|
1392
1411
|
|
|
1393
1412
|
if not all(required_params):
|
|
1394
1413
|
raise click.ClickException(FeedbackManager.error_unknown_kafka_connection(datasource=name))
|
|
@@ -1549,10 +1568,7 @@ async def process_file(
|
|
|
1549
1568
|
period: int = DEFAULT_CRON_PERIOD
|
|
1550
1569
|
|
|
1551
1570
|
if current_ws:
|
|
1552
|
-
|
|
1553
|
-
workspace_rate_limits: Dict[str, Dict[str, int]] = next(
|
|
1554
|
-
(w.get("rate_limits", {}) for w in workspaces if w["id"] == current_ws["id"]), {}
|
|
1555
|
-
)
|
|
1571
|
+
workspace_rate_limits: Dict[str, Dict[str, int]] = current_ws.get("rate_limits", {})
|
|
1556
1572
|
period = workspace_rate_limits.get("api_datasources_create_append_replace", {}).get(
|
|
1557
1573
|
"period", DEFAULT_CRON_PERIOD
|
|
1558
1574
|
)
|
|
@@ -1632,7 +1648,7 @@ async def process_file(
|
|
|
1632
1648
|
deps = []
|
|
1633
1649
|
nodes: List[Dict[str, Any]] = []
|
|
1634
1650
|
|
|
1635
|
-
is_copy = any(
|
|
1651
|
+
is_copy = any(node for node in doc.nodes if node.get("type", "standard").lower() == PipeNodeTypes.COPY)
|
|
1636
1652
|
for node in doc.nodes:
|
|
1637
1653
|
sql = node["sql"]
|
|
1638
1654
|
node_type = node.get("type", "standard").lower()
|
|
@@ -2912,7 +2928,7 @@ async def new_pipe(
|
|
|
2912
2928
|
current_pipe = r.json() if r.status_code == 200 else None
|
|
2913
2929
|
pipe_exists = current_pipe is not None
|
|
2914
2930
|
|
|
2915
|
-
is_materialized = any(
|
|
2931
|
+
is_materialized = any(node.get("params", {}).get("type", None) == "materialized" for node in p["nodes"])
|
|
2916
2932
|
copy_node = next((node for node in p["nodes"] if node.get("params", {}).get("type", None) == "copy"), None)
|
|
2917
2933
|
sink_node = next((node for node in p["nodes"] if node.get("params", {}).get("type", None) == "sink"), None)
|
|
2918
2934
|
stream_node = next((node for node in p["nodes"] if node.get("params", {}).get("type", None) == "stream"), None)
|
|
@@ -3139,7 +3155,7 @@ async def new_pipe(
|
|
|
3139
3155
|
async def share_and_unshare_datasource(
|
|
3140
3156
|
client: TinyB,
|
|
3141
3157
|
datasource: Dict[str, Any],
|
|
3142
|
-
user_token: str,
|
|
3158
|
+
user_token: Optional[str],
|
|
3143
3159
|
workspaces_current_shared_with: List[str],
|
|
3144
3160
|
workspaces_to_share: List[str],
|
|
3145
3161
|
current_ws: Optional[Dict[str, Any]],
|
|
@@ -3147,21 +3163,58 @@ async def share_and_unshare_datasource(
|
|
|
3147
3163
|
datasource_name = datasource.get("name", "")
|
|
3148
3164
|
datasource_id = datasource.get("id", "")
|
|
3149
3165
|
workspaces: List[Dict[str, Any]]
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3166
|
+
user_client: TinyB = deepcopy(client) if user_token else client
|
|
3167
|
+
if user_token:
|
|
3168
|
+
# We duplicate the client to use the user_token in workspace discovery and sharing operations.
|
|
3169
|
+
user_client.token = user_token
|
|
3153
3170
|
|
|
3154
3171
|
# In case we are pushing to a branch, we don't share the datasource
|
|
3155
3172
|
# FIXME: Have only once way to get the current workspace
|
|
3156
3173
|
if current_ws:
|
|
3157
3174
|
workspace = current_ws
|
|
3158
|
-
|
|
3175
|
+
elif user_token:
|
|
3159
3176
|
workspace = await client.user_workspace_branches()
|
|
3177
|
+
else:
|
|
3178
|
+
workspace = await client.workspace_info()
|
|
3160
3179
|
|
|
3161
3180
|
if workspace.get("is_branch", False):
|
|
3162
3181
|
click.echo(FeedbackManager.info_skipping_sharing_datasources_branch(datasource=datasource["name"]))
|
|
3163
3182
|
return
|
|
3164
3183
|
|
|
3184
|
+
if not user_token:
|
|
3185
|
+
workspaces_current_shared_with = [
|
|
3186
|
+
shared_workspace["name"] for shared_workspace in datasource.get("shared_with_workspaces", [])
|
|
3187
|
+
]
|
|
3188
|
+
workspace_names_need_to_share = [
|
|
3189
|
+
workspace_name
|
|
3190
|
+
for workspace_name in workspaces_to_share
|
|
3191
|
+
if workspace_name not in workspaces_current_shared_with
|
|
3192
|
+
]
|
|
3193
|
+
workspace_names_need_to_unshare = [
|
|
3194
|
+
workspace_name
|
|
3195
|
+
for workspace_name in workspaces_current_shared_with
|
|
3196
|
+
if workspace_name not in workspaces_to_share
|
|
3197
|
+
]
|
|
3198
|
+
|
|
3199
|
+
for workspace_name in workspace_names_need_to_share:
|
|
3200
|
+
await user_client.datasource_share(
|
|
3201
|
+
datasource_id=datasource_id,
|
|
3202
|
+
current_workspace_id=workspace.get("id", ""),
|
|
3203
|
+
destination_workspace_name=workspace_name,
|
|
3204
|
+
)
|
|
3205
|
+
click.echo(FeedbackManager.success_datasource_shared(datasource=datasource_name, workspace=workspace_name))
|
|
3206
|
+
|
|
3207
|
+
for workspace_name in workspace_names_need_to_unshare:
|
|
3208
|
+
await user_client.datasource_unshare(
|
|
3209
|
+
datasource_id=datasource_id,
|
|
3210
|
+
current_workspace_id=workspace.get("id", ""),
|
|
3211
|
+
destination_workspace_name=workspace_name,
|
|
3212
|
+
)
|
|
3213
|
+
click.echo(
|
|
3214
|
+
FeedbackManager.success_datasource_unshared(datasource=datasource_name, workspace=workspace_name)
|
|
3215
|
+
)
|
|
3216
|
+
return
|
|
3217
|
+
|
|
3165
3218
|
# Use the user token for workspace discovery, as workspace/admin tokens may not list all targets.
|
|
3166
3219
|
workspaces = (await user_client.user_workspaces()).get("workspaces", [])
|
|
3167
3220
|
if not workspaces_current_shared_with:
|
|
@@ -3245,8 +3298,12 @@ async def new_ds(
|
|
|
3245
3298
|
scopes.append(sc)
|
|
3246
3299
|
await client.alter_tokens(token_name, scopes)
|
|
3247
3300
|
|
|
3301
|
+
can_manage_shared_with = bool(user_token or (current_ws and current_ws.get("can_manage_datasources")))
|
|
3302
|
+
|
|
3248
3303
|
try:
|
|
3249
|
-
existing_ds = await client.get_datasource(
|
|
3304
|
+
existing_ds = await client.get_datasource(
|
|
3305
|
+
ds_name, include_workspace_names=can_manage_shared_with and not user_token
|
|
3306
|
+
)
|
|
3250
3307
|
datasource_exists = True
|
|
3251
3308
|
except DoesNotExistException:
|
|
3252
3309
|
datasource_exists = False
|
|
@@ -3304,7 +3361,7 @@ async def new_ds(
|
|
|
3304
3361
|
await manage_tokens()
|
|
3305
3362
|
|
|
3306
3363
|
if ds.get("shared_with"):
|
|
3307
|
-
if not
|
|
3364
|
+
if not can_manage_shared_with:
|
|
3308
3365
|
click.echo(FeedbackManager.info_skipping_shared_with_entry())
|
|
3309
3366
|
else:
|
|
3310
3367
|
await share_and_unshare_datasource(
|
|
@@ -3324,7 +3381,7 @@ async def new_ds(
|
|
|
3324
3381
|
raise click.ClickException(FeedbackManager.error_datasource_already_exists(datasource=ds_name))
|
|
3325
3382
|
|
|
3326
3383
|
if ds.get("shared_with", []) or existing_ds.get("shared_with", []):
|
|
3327
|
-
if not
|
|
3384
|
+
if not can_manage_shared_with:
|
|
3328
3385
|
click.echo(FeedbackManager.info_skipping_shared_with_entry())
|
|
3329
3386
|
else:
|
|
3330
3387
|
await share_and_unshare_datasource(
|
|
@@ -3361,7 +3418,7 @@ async def new_ds(
|
|
|
3361
3418
|
existing = existing_ds.get("indexes", [])
|
|
3362
3419
|
new.sort(key=lambda x: x["name"])
|
|
3363
3420
|
existing.sort(key=lambda x: x["name"])
|
|
3364
|
-
if len(existing) != len(new) or any(
|
|
3421
|
+
if len(existing) != len(new) or any((d, d2) for d, d2 in zip(new, existing) if d != d2):
|
|
3365
3422
|
new_indices = ds.get("params", {}).get("indexes") or "0"
|
|
3366
3423
|
if (
|
|
3367
3424
|
new_description
|
|
@@ -3561,7 +3618,7 @@ async def new_token(token: Dict[str, Any], client: TinyB, force: bool = False):
|
|
|
3561
3618
|
|
|
3562
3619
|
if force:
|
|
3563
3620
|
ADMIN_SCOPES = ["ADMIN", "ADMIN_USER"]
|
|
3564
|
-
if any(
|
|
3621
|
+
if any(scope["type"] in ADMIN_SCOPES for scope in existing_token["scopes"]):
|
|
3565
3622
|
raise click.ClickException(FeedbackManager.error_token_cannot_be_overriden(token=token["name"]))
|
|
3566
3623
|
|
|
3567
3624
|
await client.token_update(token)
|
|
@@ -4004,7 +4061,7 @@ async def build_graph(
|
|
|
4004
4061
|
if (
|
|
4005
4062
|
fork_downstream
|
|
4006
4063
|
and r.get("resource", "") == "pipes"
|
|
4007
|
-
and any(
|
|
4064
|
+
and any("engine" in x.get("params", {}) for x in r.get("nodes", []))
|
|
4008
4065
|
):
|
|
4009
4066
|
raise click.ClickException(FeedbackManager.error_forkdownstream_pipes_with_engine(pipe=fn))
|
|
4010
4067
|
|
|
@@ -4036,13 +4093,10 @@ async def build_graph(
|
|
|
4036
4093
|
|
|
4037
4094
|
# In case the datasource is to be shared and we have mapping, let's replace the name
|
|
4038
4095
|
if "shared_with" in r and workspace_map:
|
|
4039
|
-
mapped_workspaces: List[str] = [
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
if workspace_map.get(shared_with, None) is not None
|
|
4044
|
-
else shared_with # type: ignore
|
|
4045
|
-
)
|
|
4096
|
+
mapped_workspaces: List[str] = [
|
|
4097
|
+
workspace_map.get(shared_with) if workspace_map.get(shared_with, None) is not None else shared_with # type: ignore
|
|
4098
|
+
for shared_with in r["shared_with"]
|
|
4099
|
+
]
|
|
4046
4100
|
r["shared_with"] = mapped_workspaces
|
|
4047
4101
|
|
|
4048
4102
|
dep_map[fn] = set(dep_list)
|
|
@@ -4243,10 +4297,13 @@ async def folder_push(
|
|
|
4243
4297
|
hide_folders: bool = False,
|
|
4244
4298
|
on_demand_compute: bool = False,
|
|
4245
4299
|
):
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4300
|
+
if tb_client.semver:
|
|
4301
|
+
workspaces: List[Dict[str, Any]] = (await tb_client.user_workspaces_and_branches()).get("workspaces", [])
|
|
4302
|
+
current_ws: Dict[str, Any] = next(
|
|
4303
|
+
(workspace for workspace in workspaces if config and workspace.get("id", ".") == config.get("id", "..")), {}
|
|
4304
|
+
)
|
|
4305
|
+
else:
|
|
4306
|
+
current_ws = await tb_client.workspace_info()
|
|
4250
4307
|
is_branch = current_ws.get("is_branch", False)
|
|
4251
4308
|
has_semver: bool = release_created or False
|
|
4252
4309
|
|
|
@@ -5557,7 +5614,7 @@ def is_materialized(resource: Optional[Dict[str, Any]]) -> bool:
|
|
|
5557
5614
|
return False
|
|
5558
5615
|
|
|
5559
5616
|
is_materialized = any(
|
|
5560
|
-
|
|
5617
|
+
node.get("params", {}).get("type", None) == "materialized" for node in resource.get("nodes", []) or []
|
|
5561
5618
|
)
|
|
5562
5619
|
return is_materialized
|
|
5563
5620
|
|
|
@@ -5636,7 +5693,7 @@ async def create_release(
|
|
|
5636
5693
|
def has_internal_datafiles(folder: str) -> bool:
|
|
5637
5694
|
folder = folder or "."
|
|
5638
5695
|
filenames = get_project_filenames(folder)
|
|
5639
|
-
return any(
|
|
5696
|
+
return any(f for f in filenames if "spans" in str(f) and "vendor" not in str(f))
|
|
5640
5697
|
|
|
5641
5698
|
|
|
5642
5699
|
def is_file_a_datasource(filename: str) -> bool:
|
tinybird/datatypes.py
CHANGED
|
@@ -117,11 +117,11 @@ def date_test(x: str) -> bool:
|
|
|
117
117
|
|
|
118
118
|
|
|
119
119
|
def datetime64_test(x: str) -> bool:
|
|
120
|
-
return any(
|
|
120
|
+
return any(p.match(x) for p in datetime64_patterns)
|
|
121
121
|
|
|
122
122
|
|
|
123
123
|
def datetime_test(x: str) -> bool:
|
|
124
|
-
return any(
|
|
124
|
+
return any(p.match(x) for p in datetime_patterns)
|
|
125
125
|
|
|
126
126
|
|
|
127
127
|
def int_8_test(x: str) -> bool:
|
tinybird/sql_template.py
CHANGED
|
@@ -2826,7 +2826,7 @@ def render_sql_template(
|
|
|
2826
2826
|
return Comment("error launched")
|
|
2827
2827
|
|
|
2828
2828
|
v: dict = {x["name"]: Placeholder(x["name"], x["line"]) for x in template_variables}
|
|
2829
|
-
is_tb_secret = any(
|
|
2829
|
+
is_tb_secret = any(s for s in template_variables if s["name"] == "tb_secret" or s["name"] == "tb_var")
|
|
2830
2830
|
|
|
2831
2831
|
if variables:
|
|
2832
2832
|
v.update(variables)
|
tinybird/sql_toolset.py
CHANGED
|
@@ -22,7 +22,7 @@ VALID_REMOTE = "VALID_REMOTE"
|
|
|
22
22
|
|
|
23
23
|
class InvalidFunction(ValueError):
|
|
24
24
|
def __init__(self, msg: str = "", table_function_name: str = ""):
|
|
25
|
-
if any(
|
|
25
|
+
if any(fn for fn in COPY_ENABLED_TABLE_FUNCTIONS if fn in msg):
|
|
26
26
|
msg = msg.replace("is restricted", "is restricted to Copy Pipes")
|
|
27
27
|
|
|
28
28
|
if table_function_name:
|
|
@@ -58,11 +58,10 @@ async def release_ls() -> None:
|
|
|
58
58
|
async def print_releases(config: CLIConfig):
|
|
59
59
|
response = await config.get_client().releases(config["id"])
|
|
60
60
|
|
|
61
|
-
table: List[Tuple[str, str, str, str, str]] = [
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
)
|
|
61
|
+
table: List[Tuple[str, str, str, str, str]] = [
|
|
62
|
+
(release["created_at"], release["semver"], release["status"], release["commit"], release["rollback"])
|
|
63
|
+
for release in response["releases"]
|
|
64
|
+
]
|
|
66
65
|
|
|
67
66
|
columns = ["created_at", "semver", "status", "commit", "rollback release"]
|
|
68
67
|
click.echo(FeedbackManager.info_releases())
|
tinybird/tb_cli_modules/cli.py
CHANGED
|
@@ -867,9 +867,7 @@ async def sql(
|
|
|
867
867
|
if format_ == "json":
|
|
868
868
|
click.echo(json.dumps(res, indent=8))
|
|
869
869
|
else:
|
|
870
|
-
dd = []
|
|
871
|
-
for d in res["data"]:
|
|
872
|
-
dd.append(d.values())
|
|
870
|
+
dd = [d.values() for d in res["data"]]
|
|
873
871
|
echo_safe_humanfriendly_tables_format_smart_table(dd, column_names=res["data"][0].keys())
|
|
874
872
|
else:
|
|
875
873
|
click.echo(FeedbackManager.info_no_rows())
|
|
@@ -747,10 +747,12 @@ async def create_workspace_branch(
|
|
|
747
747
|
async def print_data_branch_summary(client, job_id, response=None):
|
|
748
748
|
response = await client.job(job_id) if job_id else response or {"partitions": []}
|
|
749
749
|
columns = ["Data Source", "Partition", "Status", "Error"]
|
|
750
|
-
table = []
|
|
750
|
+
table: list[list] = []
|
|
751
751
|
for partition in response["partitions"]:
|
|
752
|
-
|
|
753
|
-
|
|
752
|
+
table.extend(
|
|
753
|
+
[partition["datasource"]["name"], p["partition"], p["status"], p.get("error", "")]
|
|
754
|
+
for p in partition["partitions"]
|
|
755
|
+
)
|
|
754
756
|
echo_safe_humanfriendly_tables_format_smart_table(table, column_names=columns)
|
|
755
757
|
|
|
756
758
|
|
tinybird/tb_cli_modules/job.py
CHANGED
|
@@ -36,9 +36,7 @@ async def jobs_ls(ctx: Context, status: str) -> None:
|
|
|
36
36
|
jobs = await client.jobs(status=status)
|
|
37
37
|
columns = ["id", "kind", "status", "created at", "updated at", "job url"]
|
|
38
38
|
click.echo(FeedbackManager.info_jobs())
|
|
39
|
-
table = []
|
|
40
|
-
for j in jobs:
|
|
41
|
-
table.append([j[c.replace(" ", "_")] for c in columns])
|
|
39
|
+
table = [[j[c.replace(" ", "_")] for c in columns] for j in jobs]
|
|
42
40
|
echo_safe_humanfriendly_tables_format_smart_table(table, column_names=columns)
|
|
43
41
|
click.echo("\n")
|
|
44
42
|
|
tinybird/tb_cli_modules/tag.py
CHANGED
|
@@ -28,11 +28,10 @@ async def tag_ls(ctx: Context, tag_name: Optional[str]) -> None:
|
|
|
28
28
|
the_tag = [tag for tag in response["tags"] if tag["name"] == tag_name]
|
|
29
29
|
|
|
30
30
|
columns = ["name", "id", "type"]
|
|
31
|
-
table = []
|
|
31
|
+
table: list[list] = []
|
|
32
32
|
|
|
33
33
|
if len(the_tag) > 0:
|
|
34
|
-
for resource in the_tag[0]["resources"]
|
|
35
|
-
table.append([resource["name"], resource["id"], resource["type"]])
|
|
34
|
+
table.extend([resource["name"], resource["id"], resource["type"]] for resource in the_tag[0]["resources"])
|
|
36
35
|
|
|
37
36
|
click.echo(FeedbackManager.info_tag_resources(tag_name=tag_name))
|
|
38
37
|
echo_safe_humanfriendly_tables_format_smart_table(table, column_names=columns)
|
|
@@ -55,19 +55,18 @@ async def workspace_ls(ctx: Context) -> None:
|
|
|
55
55
|
raise CLIWorkspaceException(FeedbackManager.error_unable_to_identify_main_workspace())
|
|
56
56
|
|
|
57
57
|
columns = ["name", "id", "role", "plan", "current"]
|
|
58
|
-
table = []
|
|
59
58
|
click.echo(FeedbackManager.info_workspaces())
|
|
60
59
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
[
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
60
|
+
table = [
|
|
61
|
+
[
|
|
62
|
+
workspace["name"],
|
|
63
|
+
workspace["id"],
|
|
64
|
+
workspace["role"],
|
|
65
|
+
_get_workspace_plan_name(workspace["plan"]),
|
|
66
|
+
current_main_workspace["id"] == workspace["id"],
|
|
67
|
+
]
|
|
68
|
+
for workspace in response["workspaces"]
|
|
69
|
+
]
|
|
71
70
|
|
|
72
71
|
echo_safe_humanfriendly_tables_format_smart_table(table, column_names=columns)
|
|
73
72
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: tinybird_cli
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.5.1.dev0
|
|
4
4
|
Summary: Tinybird Command Line Tool
|
|
5
5
|
Home-page: https://www.tinybird.co/docs/cli
|
|
6
6
|
Author: Tinybird
|
|
@@ -43,6 +43,11 @@ The Tinybird command-line tool allows you to use all the Tinybird functionality
|
|
|
43
43
|
Changelog
|
|
44
44
|
----------
|
|
45
45
|
|
|
46
|
+
6.5.0
|
|
47
|
+
***********
|
|
48
|
+
|
|
49
|
+
- `Changed` `tb push` can now perform sharing and unsharing operations on Datasources with a DATASOURCES:CREATE token in workspaces in the same Organization
|
|
50
|
+
|
|
46
51
|
6.4.1
|
|
47
52
|
***********
|
|
48
53
|
|
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
tinybird/__cli__.py,sha256=
|
|
1
|
+
tinybird/__cli__.py,sha256=RC05z-Mi-JSxLkRFIXAyp1xsbVwUBLxxRlS5Xhl-7_Y,236
|
|
2
2
|
tinybird/check_pypi.py,sha256=_4NkharLyR_ELrAdit-ftqIWvOf7jZNPt3i76frlo9g,975
|
|
3
|
-
tinybird/client.py,sha256=
|
|
3
|
+
tinybird/client.py,sha256=gMgXUu7ByZ2GFPd2lLv1SzQqR49m-6vw64xCrF63r-g,52119
|
|
4
4
|
tinybird/config.py,sha256=g74rE9jbVcyFj1bms5T3VEITLr21_WFy79Uj5ovvj90,7413
|
|
5
5
|
tinybird/context.py,sha256=o4yvlXPkMLmdh-XJl3wpmqPAMeRRz5ScKzKlHHKn_I8,1201
|
|
6
|
-
tinybird/datafile_common.py,sha256=
|
|
7
|
-
tinybird/datatypes.py,sha256=
|
|
6
|
+
tinybird/datafile_common.py,sha256=qoY7vpBaGTozSbAZVBZoPeegzSw9zsVw5QuHuORJPP0,236285
|
|
7
|
+
tinybird/datatypes.py,sha256=Lr8BIaRP--qzuZFpAdv20uQaeE1BOAMmuEwWVHheFPw,11355
|
|
8
8
|
tinybird/feedback_manager.py,sha256=OehfKVruCHwUNN1bHIbDICvOaIovc3hb6RjGHTyIkBc,67667
|
|
9
9
|
tinybird/git_settings.py,sha256=mqWgeboOlOFsSo97qyv595UCR2R1QCAqT4GTawBNPBg,3935
|
|
10
10
|
tinybird/sql.py,sha256=8pvjlKwdJ-PuJkCo57W8e1gj5z0RzUP7vOnum6Pi134,48901
|
|
11
|
-
tinybird/sql_template.py,sha256=
|
|
11
|
+
tinybird/sql_template.py,sha256=_J-QmHos4Sx9YS6tVsEyE68qrcFbj13VwCA1zB3Sz8Q,128634
|
|
12
12
|
tinybird/sql_template_fmt.py,sha256=Ma4qcs-2r8ZXQC4GUmrCqYz34DsnGF8k5lE2Jwnr314,10638
|
|
13
|
-
tinybird/sql_toolset.py,sha256=
|
|
13
|
+
tinybird/sql_toolset.py,sha256=xWY-EtixaZKUPuNY4WBz2fDwwNnmbgtdLsmI2wy67UA,27220
|
|
14
14
|
tinybird/syncasync.py,sha256=rIPmCvygWSFqfnlVqhZH4N9gVVTvD6DEPsfoxGizYrI,27776
|
|
15
15
|
tinybird/tb_cli.py,sha256=q1LGAsBVVMJsjR2HK62Pu6vpVtLzNmH8wHrEVUUdVkU,744
|
|
16
16
|
tinybird/tornado_template.py,sha256=1_0nYFk_xJh_TMHh6AKkJILvnNY6xYmaM-uJ3Ofv7e8,42085
|
|
17
17
|
tinybird/ch_utils/constants.py,sha256=yTNizMzgYNBzUc2EV3moBfdrDIggOe9hiuAgWF7sv2c,4333
|
|
18
18
|
tinybird/ch_utils/engine.py,sha256=NzYUnmXsrJQimwXfCqdtIMyuS_Ad0OSdEnqNXzzStvY,37489
|
|
19
19
|
tinybird/tb_cli_modules/auth.py,sha256=3xu8STgouOgLkqlBf9LWFg9Oto_NyuDKsUWF95-zGwI,8741
|
|
20
|
-
tinybird/tb_cli_modules/branch.py,sha256
|
|
20
|
+
tinybird/tb_cli_modules/branch.py,sha256=peIo1kzBSsPGYFPOqE8qCjUlxBZURlCIoYuVTKwAQaw,39354
|
|
21
21
|
tinybird/tb_cli_modules/cicd.py,sha256=i2Mw8AbmEVNBcEPYdio7liy3PGqh1ezVFZ0OmJ9ww5o,13809
|
|
22
|
-
tinybird/tb_cli_modules/cli.py,sha256=
|
|
23
|
-
tinybird/tb_cli_modules/common.py,sha256=
|
|
22
|
+
tinybird/tb_cli_modules/cli.py,sha256=KvgZfdYRvgKG5QAiFmlfLbVGI-xmuxbs-EdkAslqrEQ,60242
|
|
23
|
+
tinybird/tb_cli_modules/common.py,sha256=WS8on_s8sGSq27YQdmMsfQ45MP9wyoJaRN_Cfrr6lUk,77275
|
|
24
24
|
tinybird/tb_cli_modules/config.py,sha256=0kFDmsDcjKon32rgFGMHHKSbv4j5dOrXtVOlyuAyEkk,11510
|
|
25
25
|
tinybird/tb_cli_modules/connection.py,sha256=yoYUQo-Fl36LTHeGI3HpFOCLiP0wKhWsoP9P9G26NZ8,21305
|
|
26
26
|
tinybird/tb_cli_modules/datasource.py,sha256=b12ClLFISGHqK7zrLZBX5OT-8Nxd2oW734-Xon0dTE8,32541
|
|
27
27
|
tinybird/tb_cli_modules/exceptions.py,sha256=pmucP4kTF4irIt7dXiG-FcnI-o3mvDusPmch1L8RCWk,3367
|
|
28
28
|
tinybird/tb_cli_modules/fmt.py,sha256=edQap4tAqWMWogSIx5zriT75naLi73XTB3NwatmcrFw,3518
|
|
29
|
-
tinybird/tb_cli_modules/job.py,sha256=
|
|
29
|
+
tinybird/tb_cli_modules/job.py,sha256=BxiqChDYa_4W4tFXHIUz2bOzkx8WMFywynjiPWgDlnE,2936
|
|
30
30
|
tinybird/tb_cli_modules/pipe.py,sha256=hIvkiGv9Zvm2KgJjFzGKjc7HQZdEmEt61yFwngXhEJ8,31672
|
|
31
31
|
tinybird/tb_cli_modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
|
|
32
|
-
tinybird/tb_cli_modules/tag.py,sha256=
|
|
32
|
+
tinybird/tb_cli_modules/tag.py,sha256=S5x8uDW0rsJEI5lKH2mefro7tEzcHyDNWrV_ZWNyS1E,3483
|
|
33
33
|
tinybird/tb_cli_modules/telemetry.py,sha256=W098H6jmS4kpE7hN3tadaREBTf7oMocel-lkKWN0pU8,10466
|
|
34
34
|
tinybird/tb_cli_modules/test.py,sha256=Vf8oK96V81HdKGsT79y6MUz6oz_VrYIwTbRnzzJs4rQ,4350
|
|
35
35
|
tinybird/tb_cli_modules/token.py,sha256=JXATKTlbXohP9ZDZjlz8E4VYG6zrknKZhuz_wh1zBBc,13793
|
|
36
|
-
tinybird/tb_cli_modules/workspace.py,sha256=
|
|
36
|
+
tinybird/tb_cli_modules/workspace.py,sha256=Ssu-jKk7lp4Gh3qX5DXhIbImyhs9aCvL09u_T75zw1I,12421
|
|
37
37
|
tinybird/tb_cli_modules/workspace_members.py,sha256=ksXsjd233y9-sNlz4Qb-meZbX4zn1B84e_bSm2i8rhg,8731
|
|
38
38
|
tinybird/tb_cli_modules/tinyunit/tinyunit.py,sha256=50uqMgJD2BqSVONtCm55nuGRWhBNZWRc2GP1Qb8URdg,11246
|
|
39
39
|
tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py,sha256=NHoXcCHPDcKWYLzgP3NViho3Ey-6RV-ynPDzySPrTPE,1817
|
|
40
|
-
tinybird_cli-6.
|
|
41
|
-
tinybird_cli-6.
|
|
42
|
-
tinybird_cli-6.
|
|
43
|
-
tinybird_cli-6.
|
|
44
|
-
tinybird_cli-6.
|
|
40
|
+
tinybird_cli-6.5.1.dev0.dist-info/METADATA,sha256=dCFUx9OV1_Sq2txVdvqrWI7vPR3eJs2SZLRzfF_kq74,81774
|
|
41
|
+
tinybird_cli-6.5.1.dev0.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
|
|
42
|
+
tinybird_cli-6.5.1.dev0.dist-info/entry_points.txt,sha256=PKPKuPmA4IfJYnCFHHUiw-aAWZuBomFvwCklv1OyCjE,43
|
|
43
|
+
tinybird_cli-6.5.1.dev0.dist-info/top_level.txt,sha256=ZIQJTPCzMqnfDzM_hEGZrJqDSEcKnIK_49T86DGWpyQ,78
|
|
44
|
+
tinybird_cli-6.5.1.dev0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|