tinybird-cli 5.1.1.dev0__tar.gz → 5.1.1.dev2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/PKG-INFO +11 -1
  2. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/__cli__.py +2 -2
  3. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/feedback_manager.py +5 -1
  4. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/sql_template.py +86 -4
  5. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/sql_toolset.py +9 -7
  6. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/pipe.py +69 -1
  7. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/workspace.py +1 -1
  8. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tornado_template.py +1 -0
  9. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird_cli.egg-info/PKG-INFO +11 -1
  10. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/setup.cfg +0 -0
  11. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/ch_utils/constants.py +0 -0
  12. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/ch_utils/engine.py +0 -0
  13. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/check_pypi.py +0 -0
  14. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/client.py +0 -0
  15. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/config.py +0 -0
  16. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/connectors.py +0 -0
  17. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/context.py +0 -0
  18. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/datafile.py +0 -0
  19. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/datatypes.py +0 -0
  20. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/git_settings.py +0 -0
  21. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/sql.py +0 -0
  22. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/sql_template_fmt.py +0 -0
  23. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/syncasync.py +0 -0
  24. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli.py +0 -0
  25. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/auth.py +0 -0
  26. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/branch.py +0 -0
  27. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/cicd.py +0 -0
  28. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/cli.py +0 -0
  29. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/common.py +0 -0
  30. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/config.py +0 -0
  31. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/connection.py +0 -0
  32. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/datasource.py +0 -0
  33. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/exceptions.py +0 -0
  34. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/job.py +0 -0
  35. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/regions.py +0 -0
  36. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/telemetry.py +0 -0
  37. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/test.py +0 -0
  38. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  39. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  40. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/token.py +0 -0
  41. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  42. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird_cli.egg-info/SOURCES.txt +0 -0
  43. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird_cli.egg-info/dependency_links.txt +0 -0
  44. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird_cli.egg-info/entry_points.txt +0 -0
  45. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird_cli.egg-info/requires.txt +0 -0
  46. {tinybird-cli-5.1.1.dev0 → tinybird-cli-5.1.1.dev2}/tinybird_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tinybird-cli
3
- Version: 5.1.1.dev0
3
+ Version: 5.1.1.dev2
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -18,6 +18,16 @@ The Tinybird command-line tool allows you to use all the Tinybird functionality
18
18
  Changelog
19
19
  ----------
20
20
 
21
+ 5.1.1.dev2
22
+ ************
23
+
24
+ - `Added` `tb pipe unlink` command
25
+
26
+ 5.1.1.dev1
27
+ ***********
28
+
29
+ - `Added` internal release
30
+
21
31
  5.1.0
22
32
  ******
23
33
 
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
4
4
  __url__ = 'https://www.tinybird.co/docs/cli/introduction.html'
5
5
  __author__ = 'Tinybird'
6
6
  __author_email__ = 'support@tinybird.co'
7
- __version__ = '5.1.1.dev0'
8
- __revision__ = '1b678aa'
7
+ __version__ = '5.1.1.dev2'
8
+ __revision__ = '1417339'
@@ -357,6 +357,7 @@ class FeedbackManager:
357
357
  error_number_of_fixed_params_and_resources_mismatch = error_message(
358
358
  "The number of --fixed-params options must not exceed the number of --scope and --resource options."
359
359
  )
360
+ error_unlinking_pipe_not_linked = error_message("** {pipe} is not linked (MV, Copy, or Sink).")
360
361
 
361
362
  info_incl_relative_path = info_message("** Relative path {path} does not exist, skipping.")
362
363
  info_ignoring_incl_file = info_message(
@@ -670,7 +671,9 @@ Ready? """
670
671
  info_materialized_datasource_used = info_message(
671
672
  "** Materialized pipe '{pipe}' using the Data Source '{datasource}'"
672
673
  )
673
- info_materialized_unlinking_pipe = info_message("** Unlinking materialized pipe {pipe}")
674
+ info_unlinking_materialized_pipe = info_message("** Unlinking materialized pipe {pipe}")
675
+ info_unlinking_copy_pipe = info_message("** Unlinking copy pipe {pipe}")
676
+ info_unlinking_sink_pipe = info_message("** Unlinking sink pipe {pipe}")
674
677
  info_materialized_unlinking_pipe_not_found = info_message("** {pipe} not found")
675
678
  info_materialized_dry_unlinking_pipe = info_message("** [DRY RUN] Unlinking materialized pipe {pipe}")
676
679
  info_copy_datasource_created = info_message("** Copy pipe '{pipe}' created the Data Source '{datasource}'")
@@ -839,6 +842,7 @@ Ready? """
839
842
  ** Pipe URL: {host}/v0/pipes/{pipe}
840
843
  """
841
844
  )
845
+ success_pipe_unlinked = success_message("""** Pipe {pipe} unlinked""")
842
846
  success_node_copy = success_message(
843
847
  """** Node set to be used to copy data!
844
848
  ** Pipe URL: {host}/v0/pipes/{pipe}
@@ -17,6 +17,36 @@ from tinybird.context import ff_preprocess_parameters_circuit_breaker, ff_split_
17
17
  from .datatypes import testers
18
18
  from .tornado_template import VALID_CUSTOM_FUNCTION_NAMES, SecurityException, Template
19
19
 
20
+ TB_SECRET_IN_TEST_MODE = "tb_secret_dont_raise"
21
+ TB_SECRET_PREFIX = "tb_secret_"
22
+ CH_PARAM_PREFIX = "param_"
23
+
24
+
25
+ def secret_template_key(secret_name: str) -> str:
26
+ return f"{TB_SECRET_PREFIX}{secret_name}"
27
+
28
+
29
+ def is_secret_template_key(key: str) -> bool:
30
+ return key.startswith(TB_SECRET_PREFIX)
31
+
32
+
33
+ class TemplateExecutionResults(dict):
34
+ def __init__(self, *args, **kwargs):
35
+ super(TemplateExecutionResults, self).__init__(*args, **kwargs)
36
+ self.template_params = set()
37
+ self.ch_params = set()
38
+
39
+ def add_template_param(self, param: str):
40
+ self.template_params.add(param)
41
+
42
+ def add_ch_param(self, param: str):
43
+ self.ch_params.add(param)
44
+
45
+ def update_all(self, other: "TemplateExecutionResults"):
46
+ self.update(other)
47
+ self.ch_params.update(other.ch_params)
48
+ self.template_params.update(other.template_params)
49
+
20
50
 
21
51
  class SQLTemplateCustomError(Exception):
22
52
  def __init__(self, err, code=400):
@@ -1333,10 +1363,30 @@ for p in DEFAULT_PARAM_NAMES: # we handle these in an specific manner
1333
1363
  error_vars = ["error", "custom_error"]
1334
1364
 
1335
1365
 
1336
- def generate(self, **kwargs) -> Tuple[str, dict]:
1366
+ def generate(self, **kwargs) -> Tuple[str, TemplateExecutionResults]:
1337
1367
  """Generate this template with the given arguments."""
1338
1368
  namespace = {}
1339
- template_execution_results = {}
1369
+ template_execution_results = TemplateExecutionResults()
1370
+ for key in kwargs.get("tb_secrets", []):
1371
+ if is_secret_template_key(key):
1372
+ template_execution_results.add_template_param(key)
1373
+ if TB_SECRET_IN_TEST_MODE in kwargs:
1374
+ template_execution_results[TB_SECRET_IN_TEST_MODE] = None
1375
+
1376
+ def set_tb_secret(x):
1377
+ try:
1378
+ key = secret_template_key(x)
1379
+ if key in template_execution_results.template_params:
1380
+ template_execution_results.add_ch_param(x)
1381
+ return Symbol("{" + sqlescape(x) + ": String}")
1382
+ else:
1383
+ is_test_mode = TB_SECRET_IN_TEST_MODE in template_execution_results
1384
+ if is_test_mode:
1385
+ return Symbol("{" + sqlescape(x) + ": String}")
1386
+ else:
1387
+ raise SQLTemplateException(f"Secret '{x}' does not exist in Workspace")
1388
+ except Exception:
1389
+ raise SQLTemplateException(f"Secret '{x}' does not exist in Workspace")
1340
1390
 
1341
1391
  def set_max_threads(x):
1342
1392
  try:
@@ -1374,6 +1424,7 @@ def generate(self, **kwargs) -> Tuple[str, dict]:
1374
1424
  "__name__": self.name.replace(".", "_"),
1375
1425
  "__loader__": ObjectDict(get_source=lambda name: self.code),
1376
1426
  "max_threads": set_max_threads,
1427
+ "tb_secret": set_tb_secret,
1377
1428
  "backend_hint": set_backend_hint,
1378
1429
  "cache_ttl": set_cache_ttl,
1379
1430
  "activate": set_activate,
@@ -1856,9 +1907,10 @@ def preprocess_variables(variables: dict, t: Template):
1856
1907
  def render_sql_template(
1857
1908
  sql: str,
1858
1909
  variables: Optional[dict] = None,
1910
+ secrets: Optional[List[str]] = None,
1859
1911
  test_mode: bool = False,
1860
1912
  name: Optional[str] = None,
1861
- ) -> Tuple[str, dict, list]:
1913
+ ) -> Tuple[str, TemplateExecutionResults, list]:
1862
1914
  """
1863
1915
  >>> render_sql_template("select * from table where f = {{Float32(foo)}}", { 'foo': -1 })
1864
1916
  ("select * from table where f = toFloat32('-1.0')", {}, [])
@@ -2058,6 +2110,20 @@ def render_sql_template(
2058
2110
  tinybird.tornado_template.UnClosedIfError: Missing {% end %} block for if at line 1
2059
2111
  >>> render_sql_template("select * from table where str = {{pipeline}}", { 'pipeline': 'test' })
2060
2112
  ("select * from table where str = 'test'", {}, ['pipeline'])
2113
+ >>> render_sql_template("select * from table where str = {{tb_secret('test')}}", secrets = [ 'tb_secret_test' ])
2114
+ ('select * from table where str = {test: String}', {}, [])
2115
+ >>> render_sql_template("select * from table where str = {{tb_secret('test')}}", variables = { 'test': '1234' })
2116
+ Traceback (most recent call last):
2117
+ ...
2118
+ tinybird.sql_template.SQLTemplateException: Template Syntax Error: Secret 'test' does not exist in Workspace
2119
+ >>> render_sql_template("select * from table where str = {{tb_secret('test')}}", test_mode=True)
2120
+ ('select * from table where str = {test: String}', {}, [])
2121
+ >>> render_sql_template("select * from table where str = {{tb_secret('test')}}", secrets = [ 'tb_secret_test' ], test_mode=True)
2122
+ ('select * from table where str = {test: String}', {}, [])
2123
+ >>> render_sql_template("select * from table where str = {{tb_secret('test')}}", secrets = [ 'tb_secret_test2' ])
2124
+ Traceback (most recent call last):
2125
+ ...
2126
+ tinybird.sql_template.SQLTemplateException: Template Syntax Error: Secret 'test' does not exist in Workspace
2061
2127
  """
2062
2128
  escape_split_to_array = ff_split_to_array_escape.get(False)
2063
2129
  bypass_preprocess_variables = ff_preprocess_parameters_circuit_breaker.get(False)
@@ -2076,10 +2142,17 @@ def render_sql_template(
2076
2142
  return Comment("error launched")
2077
2143
 
2078
2144
  v: dict = {x["name"]: Placeholder(x["name"], x["line"]) for x in template_variables}
2145
+ is_tb_secret = any([s for s in template_variables if s["name"] == "tb_secret"])
2079
2146
 
2080
2147
  if variables:
2081
2148
  v.update(variables)
2082
2149
 
2150
+ if secrets:
2151
+ v.update({"tb_secrets": secrets})
2152
+
2153
+ if is_tb_secret:
2154
+ v.update({TB_SECRET_IN_TEST_MODE: None})
2155
+
2083
2156
  v.update(type_fns_check)
2084
2157
  v.update(
2085
2158
  {
@@ -2093,10 +2166,19 @@ def render_sql_template(
2093
2166
  v = {x["name"]: None for x in template_variables}
2094
2167
  if variables:
2095
2168
  v.update(variables)
2169
+
2170
+ if secrets:
2171
+ v.update({"tb_secrets": secrets})
2096
2172
  v.update(type_fns)
2097
2173
 
2098
2174
  try:
2099
- return *generate(t, **v), variable_warnings
2175
+ sql, template_execution_results = generate(t, **v)
2176
+ try:
2177
+ if TB_SECRET_IN_TEST_MODE in template_execution_results:
2178
+ del template_execution_results[TB_SECRET_IN_TEST_MODE]
2179
+ except Exception:
2180
+ pass
2181
+ return sql, template_execution_results, variable_warnings
2100
2182
  except NameError as e:
2101
2183
  raise SQLTemplateException(e, documentation="/cli/advanced-templates.html#defined")
2102
2184
  except SQLTemplateException:
@@ -14,15 +14,15 @@ VALID_REMOTE = "VALID_REMOTE"
14
14
 
15
15
 
16
16
  class InvalidFunction(ValueError):
17
- def __init__(self, msg: str = "", table_function_names: str = ""):
17
+ def __init__(self, msg: str = "", table_function_name: str = ""):
18
18
  if any([fn for fn in COPY_ENABLED_TABLE_FUNCTIONS if fn in msg]):
19
19
  msg = msg.replace("is restricted", "is restricted to Copy Pipes")
20
20
 
21
- if table_function_names:
22
- if "postgresql" in table_function_names:
23
- self.msg = "The postgresql table function is only allowed in Copy Pipes"
21
+ if table_function_name:
22
+ if table_function_name in COPY_ENABLED_TABLE_FUNCTIONS:
23
+ self.msg = f"The {table_function_name} table function is only allowed in Copy Pipes"
24
24
  else:
25
- self.msg = f"The query uses disabled table functions: '{table_function_names}'"
25
+ self.msg = f"The query uses disabled table functions: '{table_function_name}'"
26
26
  else:
27
27
  self.msg = msg
28
28
  super().__init__(self.msg)
@@ -102,6 +102,8 @@ def sql_get_used_tables_cached(
102
102
  msg = str(e)
103
103
  if "is restricted. Contact support@tinybird.co" in msg:
104
104
  raise InvalidFunction(msg=msg) from e
105
+ elif "Unknown function tb_secret" in msg:
106
+ raise InvalidFunction(msg="Unknown function tb_secret. Usage: {{tb_secret('secret_name')}}") from e
105
107
  raise
106
108
  return [(default_database, sql, "")]
107
109
 
@@ -234,7 +236,7 @@ def replace_tables(
234
236
  if len(table) == 3:
235
237
  first_table, second_table, last_table = table
236
238
  if last_table and last_table not in _enabled_table_functions:
237
- raise InvalidFunction(table_function_names=last_table)
239
+ raise InvalidFunction(table_function_name=last_table)
238
240
  if first_table or second_table:
239
241
  table = (first_table, second_table)
240
242
  else:
@@ -251,7 +253,7 @@ def replace_tables(
251
253
  and dependent_table[2] not in _enabled_table_functions
252
254
  and not (dependent_table[2] in ["cluster"] and replacement[0] == VALID_REMOTE)
253
255
  ):
254
- raise InvalidFunction(table_function_names=dependent_table[2])
256
+ raise InvalidFunction(table_function_name=dependent_table[2])
255
257
  if dependent_table[0] or dependent_table[1]:
256
258
  dependent_table = (dependent_table[0], dependent_table[1])
257
259
  else:
@@ -16,7 +16,7 @@ from click import Context
16
16
  import tinybird.context as context
17
17
  from tinybird.client import DoesNotExistException, TinyB
18
18
  from tinybird.config import DEFAULT_API_HOST, FeatureFlags
19
- from tinybird.datafile import folder_push, get_name_version, process_file, wait_job
19
+ from tinybird.datafile import PipeTypes, folder_push, get_name_version, process_file, wait_job
20
20
  from tinybird.feedback_manager import FeedbackManager
21
21
  from tinybird.tb_cli_modules.branch import warn_if_in_live
22
22
  from tinybird.tb_cli_modules.cli import cli
@@ -267,6 +267,74 @@ async def pipe_populate(
267
267
  await wait_job(cl, job_id, job_url, "Populating")
268
268
 
269
269
 
270
+ @pipe.command(name="unlink")
271
+ @click.argument("pipe_name_or_id")
272
+ @click.argument("node_uid", default=None, required=False)
273
+ @click.pass_context
274
+ @coro
275
+ async def pipe_unlink_output_node(
276
+ ctx: click.Context,
277
+ pipe_name_or_id: str,
278
+ node_uid: Optional[str] = None,
279
+ ):
280
+ """Unlink the output of a pipe. Works for Materialized Views, Copy Pipes, and Sinks."""
281
+ client: TinyB = ctx.ensure_object(dict)["client"]
282
+
283
+ try:
284
+ pipe = await client.pipe(pipe_name_or_id)
285
+
286
+ if pipe["type"] not in [PipeTypes.MATERIALIZED, PipeTypes.COPY, PipeTypes.DATA_SINK]:
287
+ raise CLIPipeException(FeedbackManager.error_unlinking_pipe_not_linked(pipe=pipe_name_or_id))
288
+
289
+ if pipe["type"] == PipeTypes.MATERIALIZED:
290
+ click.echo(FeedbackManager.info_unlinking_materialized_pipe(pipe=pipe["name"]))
291
+
292
+ if not node_uid:
293
+ for node in pipe["nodes"]:
294
+ if "materialized" in node and node["materialized"] is not None:
295
+ node_uid = node["id"]
296
+ break
297
+
298
+ if not node_uid:
299
+ raise CLIPipeException(FeedbackManager.error_unlinking_pipe_not_linked(pipe=pipe_name_or_id))
300
+ else:
301
+ await client.pipe_unlink_materialized(pipe["name"], node_uid)
302
+ click.echo(FeedbackManager.success_pipe_unlinked(pipe=pipe["name"]))
303
+
304
+ if pipe["type"] == PipeTypes.COPY:
305
+ click.echo(FeedbackManager.info_unlinking_copy_pipe(pipe=pipe["name"]))
306
+
307
+ if not node_uid:
308
+ for node in pipe["nodes"]:
309
+ if node["node_type"] == "copy":
310
+ node_uid = node["id"]
311
+ break
312
+
313
+ if not node_uid:
314
+ raise CLIPipeException(FeedbackManager.error_unlinking_pipe_not_linked(pipe=pipe_name_or_id))
315
+ else:
316
+ await client.pipe_remove_copy(pipe["name"], node_uid)
317
+ click.echo(FeedbackManager.success_pipe_unlinked(pipe=pipe["name"]))
318
+
319
+ if pipe["type"] == PipeTypes.DATA_SINK:
320
+ click.echo(FeedbackManager.info_unlinking_sink_pipe(pipe=pipe["name"]))
321
+
322
+ if not node_uid:
323
+ for node in pipe["nodes"]:
324
+ if node["node_type"] == "sink":
325
+ node_uid = node["id"]
326
+ break
327
+
328
+ if not node_uid:
329
+ raise CLIPipeException(FeedbackManager.error_unlinking_pipe_not_linked(pipe=pipe_name_or_id))
330
+ else:
331
+ await client.pipe_remove_sink(pipe["name"], node_uid)
332
+ click.echo(FeedbackManager.success_pipe_unlinked(pipe=pipe["name"]))
333
+
334
+ except Exception as e:
335
+ raise CLIPipeException(FeedbackManager.error_exception(error=e))
336
+
337
+
270
338
  @pipe.command(name="append")
271
339
  @click.argument("pipe_name_or_uid")
272
340
  @click.argument("sql")
@@ -151,7 +151,7 @@ async def clear_workspace(ctx: Context, yes: bool, dry_run: bool) -> None:
151
151
  break
152
152
 
153
153
  if node_id:
154
- click.echo(FeedbackManager.info_materialized_unlinking_pipe(pipe=pipe["name"]))
154
+ click.echo(FeedbackManager.info_unlinking_materialized_pipe(pipe=pipe["name"]))
155
155
  try:
156
156
  await client.pipe_unlink_materialized(pipe["name"], node_id)
157
157
  except DoesNotExistException:
@@ -1050,6 +1050,7 @@ VALID_FUNCTION_NAMES = {
1050
1050
  "activate",
1051
1051
  "sql_unescape",
1052
1052
  "max_threads",
1053
+ "tb_secret",
1053
1054
  "Int",
1054
1055
  "table",
1055
1056
  "TABLE",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tinybird-cli
3
- Version: 5.1.1.dev0
3
+ Version: 5.1.1.dev2
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -18,6 +18,16 @@ The Tinybird command-line tool allows you to use all the Tinybird functionality
18
18
  Changelog
19
19
  ----------
20
20
 
21
+ 5.1.1.dev2
22
+ ************
23
+
24
+ - `Added` `tb pipe unlink` command
25
+
26
+ 5.1.1.dev1
27
+ ***********
28
+
29
+ - `Added` internal release
30
+
21
31
  5.1.0
22
32
  ******
23
33