tinybird-cli 5.9.1.dev1__tar.gz → 5.9.1.dev3__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 (48) hide show
  1. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/PKG-INFO +8 -2
  2. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/__cli__.py +2 -2
  3. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/ch_utils/engine.py +21 -1
  4. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/datafile.py +11 -7
  5. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/feedback_manager.py +3 -0
  6. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/sql.py +31 -3
  7. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/sql_template.py +22 -5
  8. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/common.py +4 -4
  9. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird_cli.egg-info/PKG-INFO +8 -2
  10. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/setup.cfg +0 -0
  11. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/ch_utils/constants.py +0 -0
  12. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/check_pypi.py +0 -0
  13. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/client.py +0 -0
  14. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/config.py +0 -0
  15. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/connectors.py +0 -0
  16. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/context.py +0 -0
  17. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/datatypes.py +0 -0
  18. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/git_settings.py +0 -0
  19. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/sql_template_fmt.py +0 -0
  20. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/sql_toolset.py +0 -0
  21. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/syncasync.py +0 -0
  22. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli.py +0 -0
  23. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/auth.py +0 -0
  24. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/branch.py +0 -0
  25. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/cicd.py +0 -0
  26. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/cli.py +0 -0
  27. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/config.py +0 -0
  28. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/connection.py +0 -0
  29. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/datasource.py +0 -0
  30. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/exceptions.py +0 -0
  31. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/fmt.py +0 -0
  32. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/job.py +0 -0
  33. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/pipe.py +0 -0
  34. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/regions.py +0 -0
  35. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/tag.py +0 -0
  36. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/telemetry.py +0 -0
  37. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/test.py +0 -0
  38. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  39. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  40. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/token.py +0 -0
  41. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/workspace.py +0 -0
  42. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  43. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird/tornado_template.py +0 -0
  44. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird_cli.egg-info/SOURCES.txt +0 -0
  45. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird_cli.egg-info/dependency_links.txt +0 -0
  46. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird_cli.egg-info/entry_points.txt +0 -0
  47. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/tinybird_cli.egg-info/requires.txt +0 -0
  48. {tinybird-cli-5.9.1.dev1 → tinybird-cli-5.9.1.dev3}/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.9.1.dev1
3
+ Version: 5.9.1.dev3
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -18,10 +18,16 @@ The Tinybird command-line tool allows you to use all the Tinybird functionality
18
18
  Changelog
19
19
  ----------
20
20
 
21
- 5.9.1.dev1
21
+ 5.9.1.dev3
22
+ ***********
23
+
24
+ - `Fixed` Correctly parse lambda expressions in indexes
25
+
26
+ 5.9.1.dev2
22
27
  ***********
23
28
 
24
29
  - `Changed` Upgrade clickhouse-toolset to 0.32.dev0
30
+ - `Added` new "File not found" error to `tb check` when including files from missing paths.
25
31
 
26
32
  5.9.0
27
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.9.1.dev1'
8
- __revision__ = '738cd9e'
7
+ __version__ = '5.9.1.dev3'
8
+ __revision__ = '6e69bc3'
@@ -4,7 +4,14 @@ from collections import defaultdict
4
4
  from dataclasses import asdict
5
5
  from typing import Any, Callable, Dict, Iterable, List, Optional
6
6
 
7
- from ..sql import TableIndex, col_name, engine_replicated_to_local, parse_indexes_structure, parse_table_structure
7
+ from ..sql import (
8
+ TableIndex,
9
+ TableProjection,
10
+ col_name,
11
+ engine_replicated_to_local,
12
+ parse_indexes_structure,
13
+ parse_table_structure,
14
+ )
8
15
 
9
16
  DEFAULT_EMPTY_PARAMETERS = ["ttl", "partition_key", "sorting_key"]
10
17
  DEFAULT_JOIN_EMPTY_PARAMETERS = ["join_strictness", "join_type", "key_columns"]
@@ -237,6 +244,10 @@ class TableDetails:
237
244
  def indexes(self) -> List[TableIndex]:
238
245
  return _parse_indexes(str(self.details.get("create_table_query", "")))
239
246
 
247
+ @property
248
+ def projections(self) -> List[TableProjection]:
249
+ return _parse_projections(self.details.get("create_table_query", ""))
250
+
240
251
  def to_json(self, exclude: Optional[List[str]] = None, include_empty_details: bool = False):
241
252
  # name, database are not exported since they are not part of the engine
242
253
  d: Dict[str, Any] = {
@@ -833,3 +844,12 @@ def _parse_indexes(create_table_query_expr: str) -> List[TableIndex]:
833
844
  return []
834
845
 
835
846
  return parse_indexes_structure(indexes)
847
+
848
+
849
+ def _parse_projections(create_table_query_expr: str) -> List[TableProjection]:
850
+ return [
851
+ TableProjection(name, expr)
852
+ for name, expr in re.findall(
853
+ r"PROJECTION\s+(\w+)\s*\(((?:[^()]|\((?:[^()]|\([^()]*\))*\))*)\)", create_table_query_expr
854
+ )
855
+ ]
@@ -278,7 +278,9 @@ class ParseException(Exception):
278
278
 
279
279
 
280
280
  class IncludeFileNotFoundException(Exception):
281
- pass
281
+ def __init__(self, err: str, lineno: int = -1):
282
+ self.lineno: int = lineno
283
+ super().__init__(err)
282
284
 
283
285
 
284
286
  class ValidationException(Exception):
@@ -584,7 +586,7 @@ class Deployment:
584
586
  self.cli_git_release.validate_local_for_release(self.current_release, check_outdated=check_outdated)
585
587
  click.echo(FeedbackManager.info_deployment_detecting_changes_header())
586
588
  commit = self.cli_git_release.get_main_branch_commit() if use_main else self.current_release["commit"]
587
- diffs = self.cli_git_release.diff_datafiles(commit)
589
+ diffs = self.cli_git_release.diff_datafiles(commit) # type: ignore
588
590
  click.echo(
589
591
  FeedbackManager.info_git_release_diffs(
590
592
  workspace=self.current_ws["name"],
@@ -863,6 +865,8 @@ def parse_pipe(
863
865
  raise click.ClickException(
864
866
  FeedbackManager.error_parsing_node_with_unclosed_if(node=e.node, pipe=filename, lineno=e.lineno, sql=e.sql)
865
867
  )
868
+ except IncludeFileNotFoundException as e:
869
+ raise click.ClickException(FeedbackManager.error_not_found_include(filename=e, lineno=e.lineno))
866
870
  except ModuleNotFoundError:
867
871
  pass
868
872
  return doc
@@ -1110,7 +1114,7 @@ def parse(
1110
1114
  StringIO(Template(file.read()).safe_substitute(attrs), newline=None)
1111
1115
  )
1112
1116
  except FileNotFoundError:
1113
- raise IncludeFileNotFoundException(f)
1117
+ raise IncludeFileNotFoundException(f, lineno)
1114
1118
 
1115
1119
  def version(*args: str, **kwargs: Any) -> None:
1116
1120
  if len(args) < 1:
@@ -1298,7 +1302,7 @@ def parse(
1298
1302
  else:
1299
1303
  raise ValidationException(f"Validation error, found {line} in line {str(lineno)}: {str(e)}", lineno=lineno)
1300
1304
  except IncludeFileNotFoundException as e:
1301
- raise e
1305
+ raise IncludeFileNotFoundException(str(e), lineno=lineno)
1302
1306
  except Exception as e:
1303
1307
  traceback.print_tb(e.__traceback__)
1304
1308
  raise ParseException(f"Unexpected error: {e}", lineno=lineno)
@@ -2114,7 +2118,7 @@ class PipeCheckerRunnerResponse:
2114
2118
 
2115
2119
 
2116
2120
  class PipeCheckerRunner:
2117
- checker_stream_result_class = unittest.runner._WritelnDecorator # type: ignore
2121
+ checker_stream_result_class = unittest.runner._WritelnDecorator
2118
2122
 
2119
2123
  def __init__(self, pipe_name: str, host: str):
2120
2124
  self.pipe_name = pipe_name
@@ -2277,7 +2281,7 @@ class PipeCheckerRunner:
2277
2281
  )
2278
2282
 
2279
2283
  result = PipeCheckerTextTestResult(
2280
- self.checker_stream_result_class(sys.stdout), descriptions=True, verbosity=2, custom_output=custom_output
2284
+ self.checker_stream_result_class(sys.stdout), descriptions=True, verbosity=2, custom_output=custom_output # type: ignore
2281
2285
  )
2282
2286
  result.failfast = failfast
2283
2287
  suite.run(result)
@@ -3985,7 +3989,7 @@ async def build_graph(
3985
3989
  mapped_workspaces.append(
3986
3990
  workspace_map.get(shared_with)
3987
3991
  if workspace_map.get(shared_with, None) is not None
3988
- else shared_with
3992
+ else shared_with # type: ignore
3989
3993
  )
3990
3994
  r["shared_with"] = mapped_workspaces
3991
3995
 
@@ -242,6 +242,9 @@ class FeedbackManager:
242
242
  error_deleted_include = error_message(
243
243
  "Related include file {include_file} was deleted and it's used in {filename}. Delete or remove dependency from {filename}."
244
244
  )
245
+ error_not_found_include = error_message(
246
+ "Included file {filename} at line {lineno} not found. Check if the file exists and the path is correct."
247
+ )
245
248
  error_branch = error_message(
246
249
  "Branch {branch} not found. use 'tb branch ls' to list your Branches, make sure you are authenticated using the right workspace token"
247
250
  )
@@ -38,11 +38,37 @@ class TableIndex:
38
38
  return f"CLEAR INDEX IF EXISTS {self.name}"
39
39
 
40
40
 
41
+ @dataclass
42
+ class TableProjection:
43
+ """Defines a CH table PROJECTION"""
44
+
45
+ name: str
46
+ expr: str
47
+
48
+ def to_datafile(self):
49
+ return f"{self.name} ({self.expr})"
50
+
51
+ def to_sql(self):
52
+ return f"PROJECTION {self.to_datafile()}"
53
+
54
+ def add_index_sql(self):
55
+ return f"ADD {self.to_sql()}"
56
+
57
+ def drop_index_sql(self):
58
+ return f"DROP PROJECTION IF EXISTS {self.name}"
59
+
60
+ def materialize_index_sql(self):
61
+ return f"MATERIALIZE PROJECTION IF EXISTS {self.name}"
62
+
63
+ def clear_index_sql(self):
64
+ return f"CLEAR PROJECTION IF EXISTS {self.name}"
65
+
66
+
41
67
  def as_subquery(sql: str) -> str:
42
68
  return f"""(\n{sql}\n)"""
43
69
 
44
70
 
45
- def get_format(sql: str) -> str:
71
+ def get_format(sql: str) -> Optional[str]:
46
72
  """
47
73
  retrieves FORMAT from CH sql
48
74
  >>> get_format('select * from test')
@@ -211,7 +237,7 @@ def format_parse_error(
211
237
  return message
212
238
 
213
239
 
214
- def parse_indexes_structure(indexes: List[str]) -> List[TableIndex]:
240
+ def parse_indexes_structure(indexes: Optional[List[str]]) -> List[TableIndex]:
215
241
  """
216
242
  >>> parse_indexes_structure(["index_name a TYPE set(100) GRANULARITY 100", "index_name_bf mapValues(d) TYPE bloom_filter(0.001) GRANULARITY 16"])
217
243
  [TableIndex(name='index_name', expr='a', type_full='set(100)', granularity='100'), TableIndex(name='index_name_bf', expr='mapValues(d)', type_full='bloom_filter(0.001)', granularity='16')]
@@ -239,6 +265,8 @@ def parse_indexes_structure(indexes: List[str]) -> List[TableIndex]:
239
265
  ValueError: invalid INDEX format. Usage: `name expr TYPE type_full GRANULARITY granularity`
240
266
  >>> parse_indexes_structure(["my_index m['key'] TYPE ngrambf_v1(1, 1024, 1, 42) GRANULARITY 1"])
241
267
  [TableIndex(name='my_index', expr="m['key']", type_full='ngrambf_v1(1, 1024, 1, 42)', granularity='1')]
268
+ >>> parse_indexes_structure(["my_index_lambda arrayMap(x -> tupleElement(x,'message'), column_name) TYPE ngrambf_v1(1, 1024, 1, 42) GRANULARITY 1"])
269
+ [TableIndex(name='my_index_lambda', expr="arrayMap(x -> tupleElement(x,'message'), column_name)", type_full='ngrambf_v1(1, 1024, 1, 42)', granularity='1')]
242
270
  >>> parse_indexes_structure(["ip_range_minmax_idx (toIPv6(ip_range_start), toIPv6(ip_range_end)) TYPE minmax GRANULARITY 1"])
243
271
  [TableIndex(name='ip_range_minmax_idx', expr='(toIPv6(ip_range_start), toIPv6(ip_range_end))', type_full='minmax', granularity='1')]
244
272
  """
@@ -253,7 +281,7 @@ def parse_indexes_structure(indexes: List[str]) -> List[TableIndex]:
253
281
  raise ValueError("invalid INDEX format. Usage: `name expr TYPE type_full GRANULARITY granularity`")
254
282
 
255
283
  match = re.match(
256
- r"(\w+)\s+([\w\s*\[\]\*\(\),\'\".]+)\s+TYPE\s+(\w+)(?:\(([\w\s*.,]+)\))?(?:\s+GRANULARITY\s+(\d+))?",
284
+ r"(\w+)\s+([\w\s*\[\]\*\(\),\'\"-><.]+)\s+TYPE\s+(\w+)(?:\(([\w\s*.,]+)\))?(?:\s+GRANULARITY\s+(\d+))?",
257
285
  index,
258
286
  )
259
287
  if match:
@@ -1619,8 +1619,10 @@ def get_var_data(content, node_id=None): # noqa: C901
1619
1619
 
1620
1620
  kwargs = {}
1621
1621
  for x in node.keywords:
1622
- kwargs[x.arg] = node_to_value(x.value)
1623
-
1622
+ value = node_to_value(x.value)
1623
+ kwargs[x.arg] = value
1624
+ if x.arg == "default":
1625
+ kwargs["default"] = check_default_value(value)
1624
1626
  if func in VALID_CUSTOM_FUNCTION_NAMES:
1625
1627
  # Type definition here is set to 'String' because it comes from a
1626
1628
  # `defined(variable)` expression that does not contain any type hint.
@@ -1628,11 +1630,15 @@ def get_var_data(content, node_id=None): # noqa: C901
1628
1630
  # args[0] check is used to avoid adding unnamed parameters found in
1629
1631
  # templates like: `split_to_array('')`
1630
1632
  if len(args) > 0 and args[0] not in vars and args[0]:
1631
- vars[args[0]] = {"type": "String", "default": None, "used_in": "function_call"}
1633
+ vars[args[0]] = {
1634
+ "type": "String",
1635
+ "default": None,
1636
+ "used_in": "function_call",
1637
+ }
1632
1638
  elif func == "Array":
1633
1639
  if "default" not in kwargs:
1634
1640
  default = kwargs.get("default", args[2] if len(args) > 2 and args[2] else None)
1635
- kwargs["default"] = default
1641
+ kwargs["default"] = check_default_value(default)
1636
1642
  if len(args):
1637
1643
  vars[args[0]] = {
1638
1644
  "type": f"Array({args[1]})" if len(args) > 1 else "Array(String)",
@@ -1644,9 +1650,11 @@ def get_var_data(content, node_id=None): # noqa: C901
1644
1650
  # if this is a cast use the function name to get the type
1645
1651
  if "default" not in kwargs:
1646
1652
  default = kwargs.get("default", args[1] if len(args) > 1 else None)
1647
- kwargs["default"] = default
1653
+ kwargs["default"] = check_default_value(default)
1648
1654
  try:
1649
1655
  vars[args[0]] = {"type": func, **kwargs}
1656
+ if "default" in kwargs:
1657
+ kwargs["default"] = check_default_value(kwargs["default"])
1650
1658
  except TypeError as e:
1651
1659
  logging.exception(f"pipe parsing problem {content} (node '{node_id}'): {e}")
1652
1660
  except Exception as e:
@@ -1665,6 +1673,13 @@ def get_var_data(content, node_id=None): # noqa: C901
1665
1673
 
1666
1674
  return vars
1667
1675
 
1676
+ def check_default_value(value):
1677
+ if isinstance(value, int):
1678
+ MAX_SAFE_INTEGER = 9007199254740991
1679
+ if value > MAX_SAFE_INTEGER:
1680
+ return str(value)
1681
+ return value
1682
+
1668
1683
  def parse_content(content, retries=0):
1669
1684
  try:
1670
1685
  parsed = ast.parse(content)
@@ -1744,6 +1759,8 @@ def get_var_names_and_types(t, node_id=None): # noqa: C901
1744
1759
  [{'name': 'symbol_id', 'type': 'Int128', 'description': 'Symbol Id', 'required': True, 'default': 11111}, {'name': 'user_id', 'type': 'Int256', 'description': 'User Id', 'default': 3555}]
1745
1760
  >>> get_var_names_and_types(Template("SELECT now() > {{DateTime64(timestamp, '2020-09-09 10:10:10.000')}}"))
1746
1761
  [{'name': 'timestamp', 'type': 'DateTime64', 'default': '2020-09-09 10:10:10.000'}]
1762
+ >>> get_var_names_and_types(Template("SELECT * FROM filter_value WHERE symbol = {{Int64(symbol_id, 9223372036854775807)}}"))
1763
+ [{'name': 'symbol_id', 'type': 'Int64', 'default': '9223372036854775807'}]
1747
1764
  """
1748
1765
  try:
1749
1766
 
@@ -1214,12 +1214,12 @@ def autocomplete_topics(ctx: Context, args, incomplete):
1214
1214
 
1215
1215
 
1216
1216
  def validate_datasource_name(name):
1217
- if not isinstance(name, str) or str == "":
1217
+ if not isinstance(name, str) or name == "":
1218
1218
  raise CLIException(FeedbackManager.error_datasource_name())
1219
1219
 
1220
1220
 
1221
1221
  def validate_connection_id(connection_id):
1222
- if not isinstance(connection_id, str) or str == "":
1222
+ if not isinstance(connection_id, str) or connection_id == "":
1223
1223
  raise CLIException(FeedbackManager.error_datasource_connection_id())
1224
1224
 
1225
1225
 
@@ -1235,7 +1235,7 @@ def validate_kafka_group(group):
1235
1235
 
1236
1236
  def validate_kafka_auto_offset_reset(auto_offset_reset):
1237
1237
  valid_values = {"latest", "earliest", "none"}
1238
- if not (auto_offset_reset in valid_values):
1238
+ if auto_offset_reset not in valid_values:
1239
1239
  raise CLIException(FeedbackManager.error_kafka_auto_offset_reset())
1240
1240
 
1241
1241
 
@@ -1588,7 +1588,7 @@ async def try_update_config_with_remote(
1588
1588
  def ask_for_admin_token_interactively(ui_host: str, default_token: Optional[str]) -> str:
1589
1589
  return (
1590
1590
  click.prompt(
1591
- f"\nCopy the \"admin your@email\" token from {ui_host}/tokens and paste it here { f'OR press enter to use the token from .tinyb file' if default_token else ''}",
1591
+ f"\nCopy the \"admin your@email\" token from {ui_host}/tokens and paste it here { 'OR press enter to use the token from .tinyb file' if default_token else ''}",
1592
1592
  hide_input=True,
1593
1593
  show_default=False,
1594
1594
  default=default_token,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tinybird-cli
3
- Version: 5.9.1.dev1
3
+ Version: 5.9.1.dev3
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -18,10 +18,16 @@ The Tinybird command-line tool allows you to use all the Tinybird functionality
18
18
  Changelog
19
19
  ----------
20
20
 
21
- 5.9.1.dev1
21
+ 5.9.1.dev3
22
+ ***********
23
+
24
+ - `Fixed` Correctly parse lambda expressions in indexes
25
+
26
+ 5.9.1.dev2
22
27
  ***********
23
28
 
24
29
  - `Changed` Upgrade clickhouse-toolset to 0.32.dev0
30
+ - `Added` new "File not found" error to `tb check` when including files from missing paths.
25
31
 
26
32
  5.9.0
27
33
  ***********