tinybird 4.6.17.dev0__tar.gz → 4.6.18__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 (127) hide show
  1. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/PKG-INFO +16 -1
  2. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/ch_utils/engine.py +7 -12
  3. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/client.py +14 -26
  4. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/datafile/common.py +20 -25
  5. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/git_settings.py +1 -3
  6. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/service_datasources.py +6 -4
  7. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/sql.py +3 -4
  8. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/sql_template.py +52 -71
  9. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/sql_template_fmt.py +8 -13
  10. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/sql_toolset.py +3 -5
  11. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/syncasync.py +9 -11
  12. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/__cli__.py +2 -2
  13. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/client.py +17 -23
  14. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/build_common.py +4 -6
  15. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/cicd.py +1 -0
  16. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/cli.py +4 -2
  17. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/common.py +10 -14
  18. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/config.py +1 -2
  19. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/connection_kafka.py +1 -2
  20. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/connection_s3.py +13 -18
  21. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/create.py +3 -6
  22. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/datafile/build.py +2 -3
  23. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/datafile/build_pipe.py +1 -4
  24. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/datafile/diff.py +2 -1
  25. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/datafile/format_common.py +9 -10
  26. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/datafile/format_connection.py +1 -2
  27. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/datafile/format_datasource.py +1 -2
  28. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/datafile/format_pipe.py +1 -2
  29. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/datafile/pipe_checker.py +6 -7
  30. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/datafile/playground.py +3 -4
  31. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/datasource.py +7 -8
  32. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/deployment_common.py +28 -7
  33. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/feedback_manager.py +1 -0
  34. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/job.py +22 -0
  35. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird.egg-info/PKG-INFO +16 -1
  36. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/setup.cfg +0 -0
  37. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/__cli__.py +0 -0
  38. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/ch_utils/constants.py +0 -0
  39. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/check_pypi.py +0 -0
  40. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/config.py +0 -0
  41. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/context.py +0 -0
  42. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/datafile/exceptions.py +0 -0
  43. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/datafile/parse_connection.py +0 -0
  44. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/datafile/parse_datasource.py +0 -0
  45. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/datafile/parse_pipe.py +0 -0
  46. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/datatypes.py +0 -0
  47. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/feedback_manager.py +0 -0
  48. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/iterating/__init__.py +0 -0
  49. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/iterating/data_branch_modes.py +0 -0
  50. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/prompts.py +0 -0
  51. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/check_pypi.py +0 -0
  52. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/cli.py +0 -0
  53. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/config.py +0 -0
  54. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/branch.py +0 -0
  55. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/build.py +0 -0
  56. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/connection.py +0 -0
  57. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/connection_dynamodb.py +0 -0
  58. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/copy.py +0 -0
  59. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/datafile/build_common.py +0 -0
  60. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  61. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/datafile/fixture.py +0 -0
  62. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/datafile/pull.py +0 -0
  63. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/deployment.py +0 -0
  64. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/deprecations.py +0 -0
  65. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/endpoint.py +0 -0
  66. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/exceptions.py +0 -0
  67. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/fmt.py +0 -0
  68. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/info.py +0 -0
  69. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/infra.py +0 -0
  70. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/job_common.py +0 -0
  71. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/llm.py +0 -0
  72. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/llm_utils.py +0 -0
  73. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/local.py +0 -0
  74. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/local_common.py +0 -0
  75. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/local_logs.py +0 -0
  76. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/login.py +0 -0
  77. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/login_common.py +0 -0
  78. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/logout.py +0 -0
  79. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/logs.py +0 -0
  80. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/materialization.py +0 -0
  81. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/open.py +0 -0
  82. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/pipe.py +0 -0
  83. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/preview.py +0 -0
  84. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/project.py +0 -0
  85. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/project_commands.py +0 -0
  86. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/py_project.py +0 -0
  87. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/query_output.py +0 -0
  88. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/regions.py +0 -0
  89. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/secret.py +0 -0
  90. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/secret_common.py +0 -0
  91. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/sink.py +0 -0
  92. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/table.py +0 -0
  93. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/telemetry.py +0 -0
  94. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/test.py +0 -0
  95. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/test_common.py +0 -0
  96. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  97. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/token.py +0 -0
  98. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/ts_project.py +0 -0
  99. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/watch.py +0 -0
  100. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/workspace.py +0 -0
  101. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb/modules/workspace_members.py +0 -0
  102. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli.py +0 -0
  103. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/auth.py +0 -0
  104. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/branch.py +0 -0
  105. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/cicd.py +0 -0
  106. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/cli.py +0 -0
  107. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/common.py +0 -0
  108. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/config.py +0 -0
  109. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/connection.py +0 -0
  110. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/datasource.py +0 -0
  111. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/exceptions.py +0 -0
  112. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/fmt.py +0 -0
  113. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/job.py +0 -0
  114. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/pipe.py +0 -0
  115. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/regions.py +0 -0
  116. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/tag.py +0 -0
  117. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/telemetry.py +0 -0
  118. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/test.py +0 -0
  119. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  120. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/workspace.py +0 -0
  121. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  122. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird/tornado_template.py +0 -0
  123. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird.egg-info/SOURCES.txt +0 -0
  124. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird.egg-info/dependency_links.txt +0 -0
  125. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird.egg-info/entry_points.txt +0 -0
  126. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird.egg-info/requires.txt +0 -0
  127. {tinybird-4.6.17.dev0 → tinybird-4.6.18}/tinybird.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 4.6.17.dev0
3
+ Version: 4.6.18
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -52,6 +52,21 @@ The Tinybird command-line tool allows you to use all the Tinybird functionality
52
52
  Changelog
53
53
  ----------
54
54
 
55
+ 4.6.18
56
+ ********
57
+
58
+ - `Fixed` CLI commands (for example ``tb migrate-to-forward``) no longer abort on startup when the best-effort refresh of the cached workspace id/name fails for a reason other than authentication.
59
+
60
+ 4.6.17
61
+ ********
62
+
63
+ - `Added` ``tb job retry <job_id>`` to retry eligible import and S3/GCS sync jobs in ``error`` or ``cancelled`` status.
64
+
65
+ 4.6.16
66
+ ********
67
+
68
+ - `Fixed` ``tb deployment promote --wait`` and ``tb deployment discard --wait`` no longer hang forever when the server reports the old/discarded deployment removal as ``failed``; the CLI now detects the failure, prints the deployment errors, and exits non-zero.
69
+
55
70
  4.6.15
56
71
  ********
57
72
 
@@ -111,8 +111,7 @@ class TableDetails:
111
111
 
112
112
  @property
113
113
  def version(self):
114
- _version = self.details.get("version", None)
115
- return _version
114
+ return self.details.get("version", None)
116
115
 
117
116
  def is_replicated(self) -> bool:
118
117
  engine: Optional[str] = self.details.get("engine", None)
@@ -183,6 +182,7 @@ class TableDetails:
183
182
  settings = self.details.get("settings", None)
184
183
  if settings and settings.strip().lower() != "index_granularity = 8192":
185
184
  return settings
185
+ return None
186
186
 
187
187
  @property
188
188
  def ttl(self):
@@ -190,23 +190,19 @@ class TableDetails:
190
190
 
191
191
  @property
192
192
  def ver(self):
193
- _ver = self.details.get("ver", None)
194
- return _ver
193
+ return self.details.get("ver", None)
195
194
 
196
195
  @property
197
196
  def is_deleted(self):
198
- _is_deleted = self.details.get("is_deleted", None)
199
- return _is_deleted
197
+ return self.details.get("is_deleted", None)
200
198
 
201
199
  @property
202
200
  def columns(self):
203
- _columns = self.details.get("columns", None)
204
- return _columns
201
+ return self.details.get("columns", None)
205
202
 
206
203
  @property
207
204
  def sign(self):
208
- _sign = self.details.get("sign", None)
209
- return _sign
205
+ return self.details.get("sign", None)
210
206
 
211
207
  @property
212
208
  def statistics(self) -> Dict[str, Any]:
@@ -699,8 +695,7 @@ def ttl_from_engine(engine: str) -> Optional[str]:
699
695
  return None
700
696
  settings_array = engine.split(" SETTINGS ")
701
697
  settings = " SETTINGS " + settings_array[1] if len(settings_array) > 1 else None
702
- ttl = ttl_array[1][: -(len(settings))] if settings else ttl_array[1]
703
- return ttl
698
+ return ttl_array[1][: -(len(settings))] if settings else ttl_array[1]
704
699
 
705
700
 
706
701
  def ttl_condition_from_engine_full(engine_full: Optional[str]) -> Optional[str]:
@@ -266,14 +266,13 @@ class TinyB:
266
266
 
267
267
  async def alter_tokens(self, name: str, scopes: List[str]):
268
268
  if not scopes:
269
- return
269
+ return None
270
270
  scopes_url: str = "&".join([f"scope={scope}" for scope in scopes])
271
271
  url = f"/v0/tokens/{name}"
272
272
  if len(url + "?" + scopes_url) > TinyB.MAX_GET_LENGTH:
273
273
  return await self._req(url, method="PUT", data=scopes_url)
274
- else:
275
- url = url + "?" + scopes_url
276
- return await self._req(url, method="PUT", data="")
274
+ url = url + "?" + scopes_url
275
+ return await self._req(url, method="PUT", data="")
277
276
 
278
277
  async def datasources(self, branch: Optional[str] = None, used_by: bool = False) -> List[Dict[str, Any]]:
279
278
  params = {}
@@ -294,16 +293,13 @@ class TinyB:
294
293
  return await self._req(f"/v0/variables/{name}")
295
294
 
296
295
  async def create_secret(self, name: str, value: str):
297
- response = await self._req("/v0/variables", method="POST", data={"name": name, "value": value})
298
- return response
296
+ return await self._req("/v0/variables", method="POST", data={"name": name, "value": value})
299
297
 
300
298
  async def update_secret(self, name: str, value: str):
301
- response = await self._req(f"/v0/variables/{name}", method="PUT", data={"value": value})
302
- return response
299
+ return await self._req(f"/v0/variables/{name}", method="PUT", data={"value": value})
303
300
 
304
301
  async def delete_secret(self, name: str):
305
- response = await self._req(f"/v0/variables/{name}", method="DELETE")
306
- return response
302
+ return await self._req(f"/v0/variables/{name}", method="DELETE")
307
303
 
308
304
  async def get_connections(self, service: Optional[str] = None):
309
305
  params = {}
@@ -577,8 +573,7 @@ class TinyB:
577
573
  node_name = node["params"]["name"] if node.get("params", None) else node["name"]
578
574
  if datasource_name:
579
575
  params["datasource"] = datasource_name
580
- response = await self._req(f"/v0/pipes/{pipe_name}/nodes/{node_name}/analysis?{urlencode(params)}")
581
- return response
576
+ return await self._req(f"/v0/pipes/{pipe_name}/nodes/{node_name}/analysis?{urlencode(params)}")
582
577
 
583
578
  async def populate_node(
584
579
  self,
@@ -600,10 +595,7 @@ class TinyB:
600
595
  params.update({"populate_condition": populate_condition})
601
596
  if on_demand_compute:
602
597
  params.update({"on_demand_compute": "true"})
603
- response = await self._req(
604
- f"/v0/pipes/{pipe_name}/nodes/{node_name}/population?{urlencode(params)}", method="POST"
605
- )
606
- return response
598
+ return await self._req(f"/v0/pipes/{pipe_name}/nodes/{node_name}/population?{urlencode(params)}", method="POST")
607
599
 
608
600
  async def pipes(self, branch=None, dependencies: bool = False, node_attrs=None, attrs=None) -> List[Dict[str, Any]]:
609
601
  params = {
@@ -635,9 +627,8 @@ class TinyB:
635
627
  query_string = urlencode(params)
636
628
  if len(url + "?" + query_string) > TinyB.MAX_GET_LENGTH:
637
629
  return await self._req(f"/v0/pipes/{pipe_name_or_uid}.{format}", method="POST", data=params)
638
- else:
639
- url = url + "?" + query_string
640
- return await self._req(url)
630
+ url = url + "?" + query_string
631
+ return await self._req(url)
641
632
 
642
633
  async def pipe_create(self, pipe_name: str, sql: str):
643
634
  return await self._req(
@@ -726,8 +717,7 @@ class TinyB:
726
717
 
727
718
  if len(sql) > TinyB.MAX_GET_LENGTH:
728
719
  return await self._req(f"/v0/sql?{urlencode(params)}", data=sql, method="POST")
729
- else:
730
- return await self._req(f"/v0/sql?q={quote(sql, safe='')}&{urlencode(params)}")
720
+ return await self._req(f"/v0/sql?q={quote(sql, safe='')}&{urlencode(params)}")
731
721
 
732
722
  async def jobs(self, status=None):
733
723
  jobs = (await self._req("/v0/jobs"))["jobs"]
@@ -922,7 +912,7 @@ class TinyB:
922
912
 
923
913
  async def add_workspaces_to_organization(self, organization_id: str, workspace_ids: List[str]):
924
914
  if not workspace_ids:
925
- return
915
+ return None
926
916
  return await self._req(
927
917
  f"/v0/organizations/{organization_id}/workspaces",
928
918
  method="PUT",
@@ -1105,8 +1095,7 @@ class TinyB:
1105
1095
  from tinybird.sql_toolset import format_sql
1106
1096
 
1107
1097
  return format_sql(sql)
1108
- else:
1109
- return await self._sql_get_format_remote(sql, with_clickhouse_format)
1098
+ return await self._sql_get_format_remote(sql, with_clickhouse_format)
1110
1099
  except ModuleNotFoundError:
1111
1100
  return await self._sql_get_format_remote(sql, with_clickhouse_format)
1112
1101
 
@@ -1168,8 +1157,7 @@ class TinyB:
1168
1157
  return next((connector for connector in result["connectors"] if connector_equals(connector, kwargs)), None)
1169
1158
 
1170
1159
  async def regions(self):
1171
- regions = await self._req("/v0/regions")
1172
- return regions
1160
+ return await self._req("/v0/regions")
1173
1161
 
1174
1162
  async def datasource_query_copy(self, datasource_name: str, sql_query: str):
1175
1163
  params = {"copy_to": datasource_name}
@@ -502,13 +502,12 @@ class Datafile:
502
502
  f"For Kafka sinks, provide 'export_kafka_topic'. "
503
503
  f"For S3/GCS sinks, provide 'export_bucket_uri' and 'export_file_template'."
504
504
  )
505
- else:
506
- # There are some export parameters, but they don't match known patterns
507
- raise DatafileValidationError(
508
- f"Sink node {repr(node['name'])} has unrecognized export parameters: {export_params}. "
509
- f"For Kafka sinks, use 'export_kafka_topic'. "
510
- f"For S3/GCS sinks, use 'export_bucket_uri' and 'export_file_template'."
511
- )
505
+ # There are some export parameters, but they don't match known patterns
506
+ raise DatafileValidationError(
507
+ f"Sink node {repr(node['name'])} has unrecognized export parameters: {export_params}. "
508
+ f"For Kafka sinks, use 'export_kafka_topic'. "
509
+ f"For S3/GCS sinks, use 'export_bucket_uri' and 'export_file_template'."
510
+ )
512
511
 
513
512
  # Validate schedule format (common for both Kafka and S3/GCS)
514
513
  export_schedule = node.get("export_schedule")
@@ -1073,8 +1072,7 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]:
1073
1072
  # Find the first SyntaxExpr in lookup that matches the schema at the current offset
1074
1073
  def lookahead_matches(lookup: Iterable) -> Optional[SyntaxExpr]:
1075
1074
  s = schema[i:]
1076
- match = next((x for x in lookup if x.regex.match(s)), None)
1077
- return match
1075
+ return next((x for x in lookup if x.regex.match(s)), None)
1078
1076
 
1079
1077
  def advance_single_char() -> None:
1080
1078
  nonlocal i, line, pos
@@ -1122,10 +1120,9 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]:
1122
1120
  )
1123
1121
  advance_single_char()
1124
1122
  return schema[begin:i]
1125
- else:
1126
- # backticked name
1127
- advance_single_char()
1128
- return get_backticked()
1123
+ # backticked name
1124
+ advance_single_char()
1125
+ return get_backticked()
1129
1126
 
1130
1127
  def parse_expr(lookup: Iterable[SyntaxExpr], attribute: str) -> str:
1131
1128
  """Parse an expression for an attribute.
@@ -1296,10 +1293,9 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]:
1296
1293
  or "incompatible data types between aggregate function" in str(e).lower()
1297
1294
  ):
1298
1295
  raise SchemaSyntaxError(message=str(e), lineno=line, pos=type_start_pos)
1299
- else:
1300
- # TODO(eclbg): The resulting error message is a bit confusing, as the clickhouse error contains some
1301
- # references to positions that don't match the position in the schema.
1302
- raise SchemaSyntaxError(f"Error parsing type: {e}", lineno=line, pos=type_start_pos)
1296
+ # TODO(eclbg): The resulting error message is a bit confusing, as the clickhouse error contains some
1297
+ # references to positions that don't match the position in the schema.
1298
+ raise SchemaSyntaxError(f"Error parsing type: {e}", lineno=line, pos=type_start_pos)
1303
1299
  except ModuleNotFoundError:
1304
1300
  pass
1305
1301
  _type = detected_type
@@ -1690,8 +1686,9 @@ def parse(
1690
1686
 
1691
1687
  if severity == "error":
1692
1688
  return raise_deprecation_error
1693
- elif severity == "warning":
1689
+ if severity == "warning":
1694
1690
  return add_deprecation_warning
1691
+ return None
1695
1692
 
1696
1693
  return inner
1697
1694
 
@@ -2238,12 +2235,11 @@ def parse(
2238
2235
  except IndexError as e:
2239
2236
  if "node" in line.lower():
2240
2237
  raise click.ClickException(FeedbackManager.error_missing_node_name())
2241
- elif "sql" in line.lower():
2238
+ if "sql" in line.lower():
2242
2239
  raise click.ClickException(FeedbackManager.error_missing_sql_command())
2243
- elif "datasource" in line.lower():
2240
+ if "datasource" in line.lower():
2244
2241
  raise click.ClickException(FeedbackManager.error_missing_datasource_name())
2245
- else:
2246
- raise ValidationException(f"Validation error, found {line} in line {str(lineno)}: {str(e)}", lineno=lineno)
2242
+ raise ValidationException(f"Validation error, found {line} in line {str(lineno)}: {str(e)}", lineno=lineno)
2247
2243
  except IncludeFileNotFoundException as e:
2248
2244
  raise IncludeFileNotFoundException(str(e), lineno=lineno)
2249
2245
  except Exception as e:
@@ -2577,12 +2573,11 @@ def get_name_version(ds: str) -> Dict[str, Any]:
2577
2573
  tk = ds.rsplit("__", 2)
2578
2574
  if len(tk) == 1:
2579
2575
  return {"name": tk[0], "version": None}
2580
- elif len(tk) == 2:
2576
+ if len(tk) == 2:
2581
2577
  if len(tk[1]):
2582
2578
  if tk[1][0] == "v" and _PATTERN_VERSION_NUMBER.match(tk[1][1:]):
2583
2579
  return {"name": tk[0], "version": int(tk[1][1:])}
2584
- else:
2585
- return {"name": tk[0] + "__" + tk[1], "version": None}
2580
+ return {"name": tk[0] + "__" + tk[1], "version": None}
2586
2581
  elif len(tk) == 3 and len(tk[2]):
2587
2582
  if tk[2] == "checker":
2588
2583
  return {"name": tk[0] + "__" + tk[1] + "__" + tk[2], "version": None}
@@ -137,9 +137,7 @@ def bump_version(version: str, next_version: Optional[str]) -> str:
137
137
 
138
138
 
139
139
  def get_default_init_files_deploy(workspace_name: str) -> Dict[str, str]:
140
- modified_files = {
140
+ return {
141
141
  path.replace("tinybird_", f"tinybird_{workspace_name.lower()}_"): content
142
142
  for path, content in DEFAULT_INIT_FILES_DEPLOY.items()
143
143
  }
144
-
145
- return modified_files
@@ -335,13 +335,14 @@ def get_tinybird_service_datasources() -> List[Dict[str, Any]]:
335
335
  ],
336
336
  },
337
337
  {
338
- "name": "tinybird.rate_limits_log",
339
- "description": "Endpoint concurrency limiter transitions in your workspace.",
338
+ "name": "tinybird.cluster_control_log",
339
+ "description": "Actions applied by cluster control in your workspace to keep the load of your cluster under control: one row every time cluster control applies, updates, or clears the concurrency limit of an endpoint. rate_limit_type is the control family, currently always endpoint_concurrency. action is the transition: applied, updated, or cleared. limit_metadata is a JSON object with the inputs of the decision and the resulting limit, read it with JSONExtract functions; its keys are max_concurrent_queries (UInt64, the limit in force after the transition), change_reason (String), analysis_window_seconds (UInt64), and the nullable estimated_qps, request_count, observed_qps, error_count, success_count, error_to_success_ratio, rate_limited_request_count, degradation_reason, pipe_cpu_time, total_cpu_time, pipe_cpu_ratio and max_cpu_ratio. This data source has a TTL of 6 months.",
340
340
  "dateColumn": "timestamp",
341
341
  "engine": {
342
342
  "engine": "MergeTree",
343
343
  "sorting_key": "timestamp, pipe_name",
344
344
  "partition_key": "toYYYYMM(timestamp)",
345
+ "ttl": "toStartOfMonth(toDateTime(timestamp)) + toIntervalMonth(6)",
345
346
  },
346
347
  "columns": [
347
348
  {"name": "timestamp", "type": "DateTime64(3)"},
@@ -732,13 +733,14 @@ def get_organization_service_datasources() -> List[Dict[str, Any]]:
732
733
  ],
733
734
  },
734
735
  {
735
- "name": "organization.rate_limits_log",
736
- "description": "Endpoint concurrency limiter transitions across the organization.",
736
+ "name": "organization.cluster_control_log",
737
+ "description": "Actions applied by cluster control across all the workspaces in your organization to keep the load of your cluster under control: one row every time cluster control applies, updates, or clears the concurrency limit of an endpoint. workspace_id and workspace_name identify the affected workspace. rate_limit_type is the control family, currently always endpoint_concurrency. action is the transition: applied, updated, or cleared. limit_metadata is a JSON object with the inputs of the decision and the resulting limit, read it with JSONExtract functions; its keys are max_concurrent_queries (UInt64, the limit in force after the transition), change_reason (String), analysis_window_seconds (UInt64), and the nullable estimated_qps, request_count, observed_qps, error_count, success_count, error_to_success_ratio, rate_limited_request_count, degradation_reason, pipe_cpu_time, total_cpu_time, pipe_cpu_ratio and max_cpu_ratio. This data source has a TTL of 6 months.",
737
738
  "dateColumn": "timestamp",
738
739
  "engine": {
739
740
  "engine": "MergeTree",
740
741
  "sorting_key": "workspace_id, timestamp, pipe_name",
741
742
  "partition_key": "toYYYYMM(timestamp)",
743
+ "ttl": "toStartOfMonth(toDateTime(timestamp)) + toIntervalMonth(6)",
742
744
  },
743
745
  "columns": [
744
746
  {"name": "timestamp", "type": "DateTime64(3)"},
@@ -675,10 +675,9 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]:
675
675
  )
676
676
  advance_single_char()
677
677
  return schema[begin:i]
678
- else:
679
- # backticked name
680
- advance_single_char()
681
- return get_backticked()
678
+ # backticked name
679
+ advance_single_char()
680
+ return get_backticked()
682
681
 
683
682
  def parse_expr(lookup: Iterable[SyntaxExpr]) -> str:
684
683
  nonlocal i, line, pos
@@ -142,8 +142,7 @@ def transform_type(
142
142
  if x is None:
143
143
  if defined:
144
144
  raise SQLTemplateException(REQUIRED_PARAM_NOT_DEFINED, documentation="/cli/advanced-templates.html")
145
- else:
146
- return None
145
+ return None
147
146
  if tester == "String":
148
147
  if x is not None:
149
148
  return transform(x)
@@ -167,12 +166,11 @@ def _and(*args, **kwargs):
167
166
  tk = k.rsplit("__", 1)
168
167
  if len(tk) == 1:
169
168
  return "="
170
- else:
171
- if tk[1] in operands:
172
- return operands[tk[1]]
173
- raise SQLTemplateException(
174
- f"operand {tk[1]} not supported", documentation="/cli/advanced-templates.html#sql_and"
175
- )
169
+ if tk[1] in operands:
170
+ return operands[tk[1]]
171
+ raise SQLTemplateException(
172
+ f"operand {tk[1]} not supported", documentation="/cli/advanced-templates.html#sql_and"
173
+ )
176
174
 
177
175
  return Expression(
178
176
  " and ".join([f"{_name(k)} {_op(k)} {expression_wrapper(v, k)}" for k, v in kwargs.items() if v is not None])
@@ -277,8 +275,7 @@ def columns(x, default=None, fn=None):
277
275
 
278
276
  if fn:
279
277
  return Expression(",".join(f"{fn}({str(column(c, c))}) as {c}" for c in _columns))
280
- else:
281
- return Expression(",".join(str(column(c, c)) for c in _columns))
278
+ return Expression(",".join(str(column(c, c)) for c in _columns))
282
279
 
283
280
 
284
281
  def column(x, default=None):
@@ -368,11 +365,10 @@ def boolean(x, default=None):
368
365
  if default is None:
369
366
  return 0
370
367
  return boolean(default)
371
- elif isinstance(x, Placeholder):
368
+ if isinstance(x, Placeholder):
372
369
  return boolean(default)
373
- elif isinstance(x, str):
374
- if x == "0" or x.lower() == "false":
375
- return 0
370
+ if isinstance(x, str) and (x == "0" or x.lower() == "false"):
371
+ return 0
376
372
 
377
373
  return int(bool(x))
378
374
 
@@ -403,8 +399,7 @@ def array_type(types):
403
399
  raise SQLTemplateException(
404
400
  REQUIRED_PARAM_NOT_DEFINED, documentation="/cli/advanced-templates.html"
405
401
  )
406
- else:
407
- return None
402
+ return None
408
403
  values = []
409
404
  list_values = x if type(x) == list else x.split(",") # noqa: E721
410
405
  for i, t in enumerate(list_values):
@@ -744,12 +739,11 @@ def __date_diff(
744
739
 
745
740
  if unit == "days":
746
741
  return int(diff / 86400)
747
- elif unit == "hours":
742
+ if unit == "hours":
748
743
  return int(diff / 3600)
749
- elif unit == "minutes":
744
+ if unit == "minutes":
750
745
  return int(diff / 60)
751
- else:
752
- return int(diff)
746
+ return int(diff)
753
747
  except Exception:
754
748
  if none_if_error:
755
749
  return None
@@ -1348,9 +1342,9 @@ def escape_single_quote_str(s):
1348
1342
  def expression_wrapper(x, name, escape_arrays: bool = False):
1349
1343
  if type(x) in (unicode_type, bytes, str):
1350
1344
  return "'" + sqlescape_for_string_expression(x) + "'"
1351
- elif isinstance(x, Placeholder):
1345
+ if isinstance(x, Placeholder):
1352
1346
  return "'__no_value__'"
1353
- elif isinstance(x, Comment):
1347
+ if isinstance(x, Comment):
1354
1348
  return "-- {x} \n"
1355
1349
  if x is None:
1356
1350
  truncated_name = name[:20] + "..." if len(name) > 20 else name
@@ -1361,10 +1355,7 @@ def expression_wrapper(x, name, escape_arrays: bool = False):
1361
1355
  logging.warning(f"expression_wrapper -> list :{x}:")
1362
1356
 
1363
1357
  try:
1364
- result = (
1365
- f"[{','.join(escape_single_quote_str(item) if isinstance(item, str) else str(item) for item in x)}]"
1366
- )
1367
- return result
1358
+ return f"[{','.join(escape_single_quote_str(item) if isinstance(item, str) else str(item) for item in x)}]"
1368
1359
  except Exception as e:
1369
1360
  logging.error(f"Error escaping array: {e}")
1370
1361
  return x
@@ -1425,20 +1416,18 @@ def generate(self, **kwargs) -> Tuple[str, TemplateExecutionResults]:
1425
1416
  # secret available: Always use workspace secret regardless of test mode
1426
1417
  template_execution_results.add_ch_param(x)
1427
1418
  return Symbol("{" + sqlescape(x) + ": String}")
1428
- else:
1429
- # secret not available: Check test mode and defaults
1430
- is_test_mode = TB_SECRET_IN_TEST_MODE in template_execution_results
1431
- if default is not None:
1432
- # Use provided default value
1433
- return default
1434
- elif is_test_mode:
1435
- # In test mode without default - return placeholder
1436
- return Symbol("{" + sqlescape(x) + ": String}")
1437
- else:
1438
- # Not in test mode, no secret, no default - raise error
1439
- raise SQLTemplateException(
1440
- f"Cannot access secret '{x}'. Check the secret exists in the Workspace and the token has the required scope."
1441
- )
1419
+ # secret not available: Check test mode and defaults
1420
+ is_test_mode = TB_SECRET_IN_TEST_MODE in template_execution_results
1421
+ if default is not None:
1422
+ # Use provided default value
1423
+ return default
1424
+ if is_test_mode:
1425
+ # In test mode without default - return placeholder
1426
+ return Symbol("{" + sqlescape(x) + ": String}")
1427
+ # Not in test mode, no secret, no default - raise error
1428
+ raise SQLTemplateException(
1429
+ f"Cannot access secret '{x}'. Check the secret exists in the Workspace and the token has the required scope."
1430
+ )
1442
1431
  except Exception:
1443
1432
  raise SQLTemplateException(
1444
1433
  f"Cannot access secret '{x}'. Check the secret exists in the Workspace and the token has the required scope."
@@ -1522,14 +1511,12 @@ def generate(self, **kwargs) -> Tuple[str, TemplateExecutionResults]:
1522
1511
 
1523
1512
  if line:
1524
1513
  raise SQLTemplateException(f"{message.strip()} line {line[0]}")
1525
- else:
1526
- raise SQLTemplateException(f"{message.strip()}")
1514
+ raise SQLTemplateException(f"{message.strip()}")
1527
1515
  except Exception as e:
1528
1516
  if isinstance(e, SQLTemplateException):
1529
1517
  raise e
1530
- else:
1531
- logging.exception(f"Error on unbound local error: {e}")
1532
- raise ValueError(str(e))
1518
+ logging.exception(f"Error on unbound local error: {e}")
1519
+ raise ValueError(str(e))
1533
1520
  except TypeError as e:
1534
1521
  error = str(e)
1535
1522
  if "not supported between instances of 'Placeholder' and " in str(e):
@@ -1960,29 +1947,27 @@ def get_var_data(content, node_id=None):
1960
1947
  # ast.Constant nodes, so .value holds str/bytes/int/float/bool/None.
1961
1948
  if type(x) == ast.Constant: # noqa: E721
1962
1949
  return x.value
1963
- elif type(x) == ast.Name: # noqa: E721
1950
+ if type(x) == ast.Name: # noqa: E721
1964
1951
  return x.id
1965
- elif type(x) == ast.List: # noqa: E721
1952
+ if type(x) == ast.List: # noqa: E721
1966
1953
  # List can hold different types
1967
1954
  return _get_list_var_data(x)
1968
- elif type(x) == ast.BinOp: # noqa: E721
1955
+ if type(x) == ast.BinOp: # noqa: E721
1969
1956
  # in this case there could be several variables
1970
1957
  # if that's the case the left one is the main
1971
1958
  r = node_to_value(x.left)
1972
1959
  if not r:
1973
1960
  r = node_to_value(x.right)
1974
1961
  return r
1975
- elif type(x) == ast.UnaryOp and type(x.operand) == ast.Constant: # noqa: E721
1962
+ if type(x) == ast.UnaryOp and type(x.operand) == ast.Constant: # noqa: E721
1976
1963
  if type(x.op) == ast.USub: # noqa: E721
1977
1964
  return x.operand.value * -1
1978
- else:
1979
- return x.operand.value
1980
- else:
1981
- try:
1982
- return x.id
1983
- except Exception:
1984
- # don't let this ruin the parsing
1985
- pass
1965
+ return x.operand.value
1966
+ try:
1967
+ return x.id
1968
+ except Exception:
1969
+ # don't let this ruin the parsing
1970
+ pass
1986
1971
  return None
1987
1972
 
1988
1973
  def _get_list_var_data(x):
@@ -1994,7 +1979,7 @@ def get_var_data(content, node_id=None):
1994
1979
  # ast.Bytes/ast.Str/ast.Num/ast.NameConstant (removed in 3.14).
1995
1980
  if type(first_elem) == ast.Constant: # noqa: E721
1996
1981
  return [elem.value for elem in x.elts]
1997
- elif type(first_elem) == ast.Name: # noqa: E721
1982
+ if type(first_elem) == ast.Name: # noqa: E721
1998
1983
  return [elem.id for elem in x.elts]
1999
1984
 
2000
1985
  return []
@@ -2013,8 +1998,7 @@ def get_var_data(content, node_id=None):
2013
1998
  # to just `ast.parse(content)` once we confirm all environments use patched Python versions.
2014
1999
  def parse_content(content, retries=0):
2015
2000
  try:
2016
- parsed = ast.parse(content)
2017
- return parsed
2001
+ return ast.parse(content)
2018
2002
  except Exception as e:
2019
2003
  if "AST constructor recursion depth mismatch" not in str(e):
2020
2004
  raise e
@@ -2042,8 +2026,7 @@ def get_var_data(content, node_id=None):
2042
2026
  if type(x) == ast.Call: # noqa: E721
2043
2027
  # Nested calls are traversed via `ast.iter_child_nodes` below.
2044
2028
  continue
2045
- else:
2046
- args.append(node_to_value(x))
2029
+ args.append(node_to_value(x))
2047
2030
 
2048
2031
  kwargs = {}
2049
2032
  for x in node.keywords:
@@ -2531,8 +2514,7 @@ def format_SQLTemplateException_message(e: SQLTemplateException, vars_and_types:
2531
2514
  f"{REQUIRED_PARAM_NOT_DEFINED}. Check the parameters {join_with_different_last_separator(vars_with_default_none)}. Please provide a value or set a default value in the pipe code.",
2532
2515
  e.documentation,
2533
2516
  )
2534
- else:
2535
- raise e
2517
+ raise e
2536
2518
 
2537
2519
 
2538
2520
  def render_sql_template(
@@ -2913,12 +2895,12 @@ def render_sql_template(
2913
2895
  # https://gitlab.com/tinybird/analytics/-/issues/943
2914
2896
  if "length" in v and not v["length"]:
2915
2897
  raise SQLTemplateException("length cannot be used as a variable name or as a function inside of a template")
2916
- elif "missing 1 required positional argument" in str(e):
2898
+ if "missing 1 required positional argument" in str(e):
2917
2899
  raise SQLTemplateException(
2918
2900
  "one of the transform type functions is missing an argument",
2919
2901
  documentation="/cli/advanced-templates.html#transform-types-functions",
2920
2902
  )
2921
- elif "not callable" in str(e) or "unhashable type" in str(e):
2903
+ if "not callable" in str(e) or "unhashable type" in str(e):
2922
2904
  raise SQLTemplateException(
2923
2905
  "wrong syntax, you might be using a not valid function inside a control block",
2924
2906
  documentation="/cli/advanced-templates.html",
@@ -3063,7 +3045,7 @@ def render_template_with_secrets(
3063
3045
  )
3064
3046
  return '""'
3065
3047
  return value
3066
- elif default is not None:
3048
+ if default is not None:
3067
3049
  if isinstance(default, str) and len(default) == 0:
3068
3050
  if empty_secret_raises:
3069
3051
  raise SQLTemplateException(
@@ -3071,10 +3053,9 @@ def render_template_with_secrets(
3071
3053
  )
3072
3054
  return '""'
3073
3055
  return default
3074
- else:
3075
- raise SQLTemplateException(
3076
- f"Cannot access secret '{secret_name}'. Check the secret exists in the Workspace and the token has the required scope."
3077
- )
3056
+ raise SQLTemplateException(
3057
+ f"Cannot access secret '{secret_name}'. Check the secret exists in the Workspace and the token has the required scope."
3058
+ )
3078
3059
 
3079
3060
  # Create the template
3080
3061
  t = Template(content, name=name, autoescape=None)