tinybird 4.6.16.dev0__tar.gz → 4.6.17__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.16.dev0 → tinybird-4.6.17}/PKG-INFO +22 -1
  2. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/ch_utils/engine.py +13 -13
  3. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/client.py +14 -26
  4. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/config.py +0 -4
  5. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/datafile/common.py +41 -25
  6. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/git_settings.py +1 -3
  7. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/service_datasources.py +42 -16
  8. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/sql_toolset.py +0 -5
  9. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/__cli__.py +2 -2
  10. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/client.py +5 -2
  11. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/build_common.py +4 -6
  12. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/common.py +2 -2
  13. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/deployment.py +5 -8
  14. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/deployment_common.py +108 -15
  15. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/feedback_manager.py +1 -0
  16. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/job.py +22 -0
  17. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird.egg-info/PKG-INFO +22 -1
  18. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/setup.cfg +0 -0
  19. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/__cli__.py +0 -0
  20. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/ch_utils/constants.py +0 -0
  21. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/check_pypi.py +0 -0
  22. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/context.py +0 -0
  23. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/datafile/exceptions.py +0 -0
  24. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/datafile/parse_connection.py +0 -0
  25. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/datafile/parse_datasource.py +0 -0
  26. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/datafile/parse_pipe.py +0 -0
  27. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/datatypes.py +0 -0
  28. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/feedback_manager.py +0 -0
  29. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/iterating/__init__.py +0 -0
  30. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/iterating/data_branch_modes.py +0 -0
  31. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/prompts.py +0 -0
  32. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/sql.py +0 -0
  33. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/sql_template.py +0 -0
  34. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/sql_template_fmt.py +0 -0
  35. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/syncasync.py +0 -0
  36. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/check_pypi.py +0 -0
  37. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/cli.py +0 -0
  38. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/config.py +0 -0
  39. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/branch.py +0 -0
  40. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/build.py +0 -0
  41. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/cicd.py +0 -0
  42. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/cli.py +0 -0
  43. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/config.py +0 -0
  44. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/connection.py +0 -0
  45. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/connection_dynamodb.py +0 -0
  46. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/connection_kafka.py +0 -0
  47. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/connection_s3.py +0 -0
  48. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/copy.py +0 -0
  49. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/create.py +0 -0
  50. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/datafile/build.py +0 -0
  51. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/datafile/build_common.py +0 -0
  52. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  53. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  54. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/datafile/diff.py +0 -0
  55. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/datafile/fixture.py +0 -0
  56. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/datafile/format_common.py +0 -0
  57. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/datafile/format_connection.py +0 -0
  58. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  59. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  60. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  61. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/datafile/playground.py +0 -0
  62. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/datafile/pull.py +0 -0
  63. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/datasource.py +0 -0
  64. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/deprecations.py +0 -0
  65. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/endpoint.py +0 -0
  66. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/exceptions.py +0 -0
  67. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/fmt.py +0 -0
  68. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/info.py +0 -0
  69. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/infra.py +0 -0
  70. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/job_common.py +0 -0
  71. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/llm.py +0 -0
  72. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/llm_utils.py +0 -0
  73. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/local.py +0 -0
  74. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/local_common.py +0 -0
  75. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/local_logs.py +0 -0
  76. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/login.py +0 -0
  77. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/login_common.py +0 -0
  78. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/logout.py +0 -0
  79. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/logs.py +0 -0
  80. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/materialization.py +0 -0
  81. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/open.py +0 -0
  82. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/pipe.py +0 -0
  83. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/preview.py +0 -0
  84. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/project.py +0 -0
  85. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/project_commands.py +0 -0
  86. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/py_project.py +0 -0
  87. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/query_output.py +0 -0
  88. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/regions.py +0 -0
  89. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/secret.py +0 -0
  90. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/secret_common.py +0 -0
  91. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/sink.py +0 -0
  92. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/table.py +0 -0
  93. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/telemetry.py +0 -0
  94. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/test.py +0 -0
  95. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/test_common.py +0 -0
  96. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  97. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/token.py +0 -0
  98. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/ts_project.py +0 -0
  99. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/watch.py +0 -0
  100. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/workspace.py +0 -0
  101. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb/modules/workspace_members.py +0 -0
  102. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli.py +0 -0
  103. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/auth.py +0 -0
  104. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/branch.py +0 -0
  105. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/cicd.py +0 -0
  106. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/cli.py +0 -0
  107. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/common.py +0 -0
  108. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/config.py +0 -0
  109. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/connection.py +0 -0
  110. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/datasource.py +0 -0
  111. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/exceptions.py +0 -0
  112. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/fmt.py +0 -0
  113. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/job.py +0 -0
  114. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/pipe.py +0 -0
  115. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/regions.py +0 -0
  116. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/tag.py +0 -0
  117. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/telemetry.py +0 -0
  118. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/test.py +0 -0
  119. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  120. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/workspace.py +0 -0
  121. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  122. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird/tornado_template.py +0 -0
  123. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird.egg-info/SOURCES.txt +0 -0
  124. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird.egg-info/dependency_links.txt +0 -0
  125. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird.egg-info/entry_points.txt +0 -0
  126. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/tinybird.egg-info/requires.txt +0 -0
  127. {tinybird-4.6.16.dev0 → tinybird-4.6.17}/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.16.dev0
3
+ Version: 4.6.17
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -51,11 +51,32 @@ The Tinybird command-line tool allows you to use all the Tinybird functionality
51
51
 
52
52
  Changelog
53
53
  ----------
54
+
55
+ 4.6.17
56
+ ********
57
+
58
+ - `Added` ``tb job retry <job_id>`` to retry eligible import and S3/GCS sync jobs in ``error`` or ``cancelled`` status.
59
+
60
+ 4.6.16
61
+ ********
62
+
63
+ - `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.
64
+
65
+ 4.6.15
66
+ ********
67
+
68
+ - `Fixed` ``tb deploy`` waits for the old deployment to delete to avoid clashing with a new deployment submission.
69
+
54
70
  4.6.14
55
71
  ********
56
72
 
57
73
  - `Changed` ``tb datasource append`` and ``tb datasource replace`` submit local CSV, NDJSON, and Parquet files through the v1 import endpoint by default. ``tb datasource append --events`` also submits its request body through v1. These asynchronous imports print the queued job ID; pass ``--wait`` to wait for completion. Remote URL imports continue to use their existing route.
58
74
 
75
+ 4.6.14
76
+ ********
77
+
78
+ - `Fixed` `tb migrate-to-forward` correctly finds and offers to delete all branches, not just those created by the user running the migration.
79
+
59
80
  4.6.13
60
81
  ********
61
82
 
@@ -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]:
@@ -476,6 +472,9 @@ def engine_options(columns, options: List[EngineOption], args: Dict):
476
472
  if option_value:
477
473
  if o.sql.lower() == "settings":
478
474
  engine_settings = f"{o.sql} {option_value}"
475
+ # Conditional TTLs fail if we wrap the value in parentheses
476
+ elif o.sql.lower() == "ttl":
477
+ options_values.append(f"{o.sql} {option_value}")
479
478
  else:
480
479
  options_values.append(f"{o.sql} ({option_value})")
481
480
 
@@ -536,7 +535,9 @@ def engine_full_from_dict(
536
535
  >>> engine_full_from_dict('MergeTree', {'sorting_key': 'local_date, cod_store'}, schema=schema)
537
536
  'MergeTree() ORDER BY (local_date, cod_store)'
538
537
  >>> engine_full_from_dict('MergeTree', {'partition_key': 'toDate(timestamp)', 'sorting_key': 'local_date, cod_store', 'settings': 'index_granularity = 32, index_granularity_bytes = 2048', 'ttl': 'toDate(local_date) + INTERVAL 1 DAY'}, schema=schema)
539
- 'MergeTree() PARTITION BY (toDate(timestamp)) ORDER BY (local_date, cod_store) TTL (toDate(local_date) + INTERVAL 1 DAY) SETTINGS index_granularity = 32, index_granularity_bytes = 2048'
538
+ 'MergeTree() PARTITION BY (toDate(timestamp)) ORDER BY (local_date, cod_store) TTL toDate(local_date) + INTERVAL 1 DAY SETTINGS index_granularity = 32, index_granularity_bytes = 2048'
539
+ >>> engine_full_from_dict('MergeTree', {'sorting_key': 'timestamp', 'ttl': 'timestamp + INTERVAL 1 DAY DELETE WHERE is_deleted = 1'}, schema=schema)
540
+ 'MergeTree() ORDER BY (timestamp) TTL timestamp + INTERVAL 1 DAY DELETE WHERE is_deleted = 1'
540
541
 
541
542
  >>> schema = ''
542
543
  >>> engine_full_from_dict('CollapsingMergeTree', {'sign': 'sign_column'}, schema=schema)
@@ -694,8 +695,7 @@ def ttl_from_engine(engine: str) -> Optional[str]:
694
695
  return None
695
696
  settings_array = engine.split(" SETTINGS ")
696
697
  settings = " SETTINGS " + settings_array[1] if len(settings_array) > 1 else None
697
- ttl = ttl_array[1][: -(len(settings))] if settings else ttl_array[1]
698
- return ttl
698
+ return ttl_array[1][: -(len(settings))] if settings else ttl_array[1]
699
699
 
700
700
 
701
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}
@@ -49,11 +49,7 @@ LEGACY_HOSTS = {
49
49
  "https://ui.europe-west2.gcp.tinybird.co": "https://cloud.tinybird.co/gcp/europe-west2",
50
50
  "https://ui.ap-east.aws.tinybird.co": "https://app.tinybird.co/aws/ap-east-1",
51
51
  "https://ui.ap-east-1.aws.tinybird.co": "https://app.tinybird.co/aws/ap-east-1",
52
- "https://ui.split.tinybird.co": "https://app.tinybird.co/aws/split-us-east",
53
- "https://ui.split.us-west-2.aws.tinybird.co": "https://app.tinybird.co/aws/split-us-west-2",
54
52
  "https://ui.northamerica-northeast2.gcp.tinybird.co": "https://app.tinybird.co/gcp/northamerica-northeast2",
55
- "https://api.split.tinybird.co": "https://app.tinybird.co/aws/split-us-east",
56
- "https://api.split.us-west-2.aws.tinybird.co": "https://app.tinybird.co/aws/split-us-west-2",
57
53
  "https://ui.wadus1.gcp.tinybird.co": "https://app.wadus.tinybird.co/gcp/wadus1",
58
54
  "https://ui.wadus2.gcp.tinybird.co": "https://app.wadus.tinybird.co/gcp/wadus2",
59
55
  "https://ui.wadus3.gcp.tinybird.co": "https://app.wadus.tinybird.co/gcp/wadus3",
@@ -278,6 +278,12 @@ REQUIRED_DYNAMODB_PARAMS = {
278
278
  }
279
279
  DYNAMODB_PARAMS = REQUIRED_DYNAMODB_PARAMS
280
280
 
281
+ REQUIRED_POSTGRES_PARAMS = {
282
+ "pg_connection_name",
283
+ "pg_table",
284
+ }
285
+ POSTGRES_PARAMS = REQUIRED_POSTGRES_PARAMS
286
+
281
287
 
282
288
  def extract_column_names_from_sorting_key_part(part: str) -> List[str]:
283
289
  """
@@ -496,13 +502,12 @@ class Datafile:
496
502
  f"For Kafka sinks, provide 'export_kafka_topic'. "
497
503
  f"For S3/GCS sinks, provide 'export_bucket_uri' and 'export_file_template'."
498
504
  )
499
- else:
500
- # There are some export parameters, but they don't match known patterns
501
- raise DatafileValidationError(
502
- f"Sink node {repr(node['name'])} has unrecognized export parameters: {export_params}. "
503
- f"For Kafka sinks, use 'export_kafka_topic'. "
504
- f"For S3/GCS sinks, use 'export_bucket_uri' and 'export_file_template'."
505
- )
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
+ )
506
511
 
507
512
  # Validate schedule format (common for both Kafka and S3/GCS)
508
513
  export_schedule = node.get("export_schedule")
@@ -602,6 +607,13 @@ class Datafile:
602
607
  raise DatafileValidationError(
603
608
  f"Invalid import schedule '{node['import_schedule']}'. Only {sorted(VALID_BLOB_STORAGE_CRON_VALUES)} values are allowed"
604
609
  )
610
+ # Validate Postgres params
611
+ if any(param in node for param in POSTGRES_PARAMS) and (
612
+ missing := [param for param in REQUIRED_POSTGRES_PARAMS if param not in node]
613
+ ):
614
+ raise DatafileValidationError(
615
+ f"Some Postgres params have been provided, but the following required ones are missing: {missing}"
616
+ )
605
617
 
606
618
  else:
607
619
  # We cannot validate a datafile whose kind is unknown
@@ -1060,8 +1072,7 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]:
1060
1072
  # Find the first SyntaxExpr in lookup that matches the schema at the current offset
1061
1073
  def lookahead_matches(lookup: Iterable) -> Optional[SyntaxExpr]:
1062
1074
  s = schema[i:]
1063
- match = next((x for x in lookup if x.regex.match(s)), None)
1064
- return match
1075
+ return next((x for x in lookup if x.regex.match(s)), None)
1065
1076
 
1066
1077
  def advance_single_char() -> None:
1067
1078
  nonlocal i, line, pos
@@ -1109,10 +1120,9 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]:
1109
1120
  )
1110
1121
  advance_single_char()
1111
1122
  return schema[begin:i]
1112
- else:
1113
- # backticked name
1114
- advance_single_char()
1115
- return get_backticked()
1123
+ # backticked name
1124
+ advance_single_char()
1125
+ return get_backticked()
1116
1126
 
1117
1127
  def parse_expr(lookup: Iterable[SyntaxExpr], attribute: str) -> str:
1118
1128
  """Parse an expression for an attribute.
@@ -1283,10 +1293,9 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]:
1283
1293
  or "incompatible data types between aggregate function" in str(e).lower()
1284
1294
  ):
1285
1295
  raise SchemaSyntaxError(message=str(e), lineno=line, pos=type_start_pos)
1286
- else:
1287
- # TODO(eclbg): The resulting error message is a bit confusing, as the clickhouse error contains some
1288
- # references to positions that don't match the position in the schema.
1289
- 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)
1290
1299
  except ModuleNotFoundError:
1291
1300
  pass
1292
1301
  _type = detected_type
@@ -1677,8 +1686,9 @@ def parse(
1677
1686
 
1678
1687
  if severity == "error":
1679
1688
  return raise_deprecation_error
1680
- elif severity == "warning":
1689
+ if severity == "warning":
1681
1690
  return add_deprecation_warning
1691
+ return None
1682
1692
 
1683
1693
  return inner
1684
1694
 
@@ -2068,6 +2078,8 @@ def parse(
2068
2078
  "import_query": assign_var("import_query"), # Deprecated, BQ and SFK
2069
2079
  "import_table_arn": assign_var("import_table_arn"), # Only for DynamoDB
2070
2080
  "import_export_bucket": assign_var("import_export_bucket"), # For DynamoDB
2081
+ "pg_connection_name": assign_var("pg_connection_name"),
2082
+ "pg_table": assign_var("pg_table"),
2071
2083
  "shared_with": shared_with,
2072
2084
  "export_service": export_service, # Deprecated
2073
2085
  "forward_query": forward_query,
@@ -2128,6 +2140,12 @@ def parse(
2128
2140
  "gcs_secret": assign_var("gcs_hmac_secret"),
2129
2141
  "gcs_hmac_access_id": assign_var("gcs_hmac_access_id"),
2130
2142
  "gcs_hmac_secret": assign_var("gcs_hmac_secret"),
2143
+ "pg_host": assign_var("pg_host"),
2144
+ "pg_port": assign_var("pg_port"),
2145
+ "pg_database": assign_var("pg_database"),
2146
+ "pg_user": assign_var("pg_user"),
2147
+ "pg_password": assign_var("pg_password"),
2148
+ "pg_ssl_mode": assign_var("pg_ssl_mode"),
2131
2149
  "include": include,
2132
2150
  },
2133
2151
  }
@@ -2217,12 +2235,11 @@ def parse(
2217
2235
  except IndexError as e:
2218
2236
  if "node" in line.lower():
2219
2237
  raise click.ClickException(FeedbackManager.error_missing_node_name())
2220
- elif "sql" in line.lower():
2238
+ if "sql" in line.lower():
2221
2239
  raise click.ClickException(FeedbackManager.error_missing_sql_command())
2222
- elif "datasource" in line.lower():
2240
+ if "datasource" in line.lower():
2223
2241
  raise click.ClickException(FeedbackManager.error_missing_datasource_name())
2224
- else:
2225
- 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)
2226
2243
  except IncludeFileNotFoundException as e:
2227
2244
  raise IncludeFileNotFoundException(str(e), lineno=lineno)
2228
2245
  except Exception as e:
@@ -2556,12 +2573,11 @@ def get_name_version(ds: str) -> Dict[str, Any]:
2556
2573
  tk = ds.rsplit("__", 2)
2557
2574
  if len(tk) == 1:
2558
2575
  return {"name": tk[0], "version": None}
2559
- elif len(tk) == 2:
2576
+ if len(tk) == 2:
2560
2577
  if len(tk[1]):
2561
2578
  if tk[1][0] == "v" and _PATTERN_VERSION_NUMBER.match(tk[1][1:]):
2562
2579
  return {"name": tk[0], "version": int(tk[1][1:])}
2563
- else:
2564
- return {"name": tk[0] + "__" + tk[1], "version": None}
2580
+ return {"name": tk[0] + "__" + tk[1], "version": None}
2565
2581
  elif len(tk) == 3 and len(tk[2]):
2566
2582
  if tk[2] == "checker":
2567
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
@@ -48,6 +48,7 @@ def get_tinybird_service_datasources() -> List[Dict[str, Any]]:
48
48
  {"name": "client_ip", "type": "Nullable(String)"},
49
49
  {"name": "resource_tags", "type": "Array(String)"},
50
50
  {"name": "memory_usage", "type": "UInt64"},
51
+ {"name": "replica", "type": "String"},
51
52
  ],
52
53
  },
53
54
  {
@@ -333,6 +334,26 @@ def get_tinybird_service_datasources() -> List[Dict[str, Any]]:
333
334
  {"name": "job_metadata", "type": "String"},
334
335
  ],
335
336
  },
337
+ {
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
+ "dateColumn": "timestamp",
341
+ "engine": {
342
+ "engine": "MergeTree",
343
+ "sorting_key": "timestamp, pipe_name",
344
+ "partition_key": "toYYYYMM(timestamp)",
345
+ "ttl": "toStartOfMonth(toDateTime(timestamp)) + toIntervalMonth(6)",
346
+ },
347
+ "columns": [
348
+ {"name": "timestamp", "type": "DateTime64(3)"},
349
+ {"name": "workspace_id", "type": "String"},
350
+ {"name": "workspace_name", "type": "String"},
351
+ {"name": "pipe_name", "type": "String"},
352
+ {"name": "rate_limit_type", "type": "LowCardinality(String)"},
353
+ {"name": "action", "type": "LowCardinality(String)"},
354
+ {"name": "limit_metadata", "type": "String"},
355
+ ],
356
+ },
336
357
  {
337
358
  "name": "tinybird.hook_log",
338
359
  "description": "Log of hook executions and their results.",
@@ -518,22 +539,6 @@ def get_organization_service_datasources() -> List[Dict[str, Any]]:
518
539
  {"name": "origin", "type": "String"},
519
540
  ],
520
541
  },
521
- {
522
- "name": "organization.processed_data",
523
- "description": "Information related to all processed data per day per workspace.",
524
- "dateColumn": "date",
525
- "engine": {
526
- "engine": "SummingMergeTree",
527
- "sorting_key": "database, date",
528
- "partition_key": "toYYYYMM(date)",
529
- },
530
- "columns": [
531
- {"name": "date", "type": "Date"},
532
- {"name": "database", "type": "String"},
533
- {"name": "read_bytes", "type": "UInt64"},
534
- {"name": "written_bytes", "type": "UInt64"},
535
- ],
536
- },
537
542
  {
538
543
  "name": "organization.datasources_storage",
539
544
  "description": "Similar to tinybird.datasources_storage but with data for all Organization Workspaces.",
@@ -683,6 +688,7 @@ def get_organization_service_datasources() -> List[Dict[str, Any]]:
683
688
  {"name": "user_agent", "type": "Nullable(String)"},
684
689
  {"name": "resource_tags", "type": "Array(String)"},
685
690
  {"name": "memory_usage", "type": "UInt64"},
691
+ {"name": "replica", "type": "String"},
686
692
  ],
687
693
  },
688
694
  {
@@ -726,6 +732,26 @@ def get_organization_service_datasources() -> List[Dict[str, Any]]:
726
732
  {"name": "job_metadata", "type": "String"},
727
733
  ],
728
734
  },
735
+ {
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.",
738
+ "dateColumn": "timestamp",
739
+ "engine": {
740
+ "engine": "MergeTree",
741
+ "sorting_key": "workspace_id, timestamp, pipe_name",
742
+ "partition_key": "toYYYYMM(timestamp)",
743
+ "ttl": "toStartOfMonth(toDateTime(timestamp)) + toIntervalMonth(6)",
744
+ },
745
+ "columns": [
746
+ {"name": "timestamp", "type": "DateTime64(3)"},
747
+ {"name": "workspace_id", "type": "String"},
748
+ {"name": "workspace_name", "type": "String"},
749
+ {"name": "pipe_name", "type": "String"},
750
+ {"name": "rate_limit_type", "type": "LowCardinality(String)"},
751
+ {"name": "action", "type": "LowCardinality(String)"},
752
+ {"name": "limit_metadata", "type": "String"},
753
+ ],
754
+ },
729
755
  {
730
756
  "name": "organization.sinks_ops_log",
731
757
  "description": "Historic Logs for all Sink job executions across the organization",
@@ -493,7 +493,6 @@ def replace_tables_chquery_cached(
493
493
  sorted_replacements: Optional[tuple] = None,
494
494
  default_database: str = "",
495
495
  output_one_line: bool = False,
496
- timestamp: Optional[datetime] = None,
497
496
  function_allow_list: Optional[FrozenSet[str]] = None,
498
497
  settings_allow_list: Optional[FrozenSet[str]] = None,
499
498
  ) -> str:
@@ -536,7 +535,6 @@ def replace_tables(
536
535
  sql,
537
536
  None,
538
537
  output_one_line=output_one_line,
539
- timestamp=timestamp,
540
538
  function_allow_list=hashable_list,
541
539
  settings_allow_list=hashable_settings_list,
542
540
  )
@@ -610,7 +608,6 @@ def replace_tables(
610
608
  sql,
611
609
  None,
612
610
  output_one_line=output_one_line,
613
- timestamp=timestamp,
614
611
  function_allow_list=hashable_list,
615
612
  settings_allow_list=hashable_settings_list,
616
613
  )
@@ -649,7 +646,6 @@ def replace_tables(
649
646
  r,
650
647
  default_database=default_database,
651
648
  output_one_line=output_one_line,
652
- timestamp=timestamp,
653
649
  function_allow_list=hashable_list,
654
650
  settings_allow_list=hashable_settings_list,
655
651
  )
@@ -658,7 +654,6 @@ def replace_tables(
658
654
  sql,
659
655
  None,
660
656
  output_one_line=output_one_line,
661
- timestamp=timestamp,
662
657
  function_allow_list=hashable_list,
663
658
  settings_allow_list=hashable_settings_list,
664
659
  )
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
4
4
  __url__ = 'https://www.tinybird.co/docs/forward/commands'
5
5
  __author__ = 'Tinybird'
6
6
  __author_email__ = 'support@tinybird.co'
7
- __version__ = '4.6.16.dev0'
8
- __revision__ = '532ee82'
7
+ __version__ = '4.6.17'
8
+ __revision__ = '92350bf'
@@ -811,6 +811,9 @@ class TinyB:
811
811
  def job_cancel(self, job_id: str):
812
812
  return self._req(f"/v0/jobs/{job_id}/cancel", method="POST", data=b"")
813
813
 
814
+ def job_retry(self, job_id: str) -> Dict[str, Any]:
815
+ return self._req(f"/v0/jobs/{job_id}/retry", method="POST", data=b"")
816
+
814
817
  def user_workspaces(self, version: str = "v0"):
815
818
  data = self._req(f"/{version}/user/workspaces/?with_environments=false")
816
819
  # TODO: this is repeated in local_common.py but I'm avoiding circular imports
@@ -833,8 +836,8 @@ class TinyB:
833
836
  def user_workspace_branches(self, version: str = "v0"):
834
837
  return self._req(f"/{version}/user/workspaces/?with_environments=true&only_environments=true")
835
838
 
836
- def branches(self):
837
- return self._req("/v1/environments")
839
+ def branches(self, version: str = "v1"):
840
+ return self._req(f"/{version}/environments")
838
841
 
839
842
  def releases(self, workspace_id):
840
843
  return self._req(f"/v0/workspaces/{workspace_id}/releases")
@@ -44,7 +44,7 @@ def process(
44
44
 
45
45
  # Ensure SHARED_WITH workspaces exist before build
46
46
  if not is_branch:
47
- build_shared_with_workspaces(project=project, tb_client=tb_client, config=config)
47
+ build_shared_with_workspaces(project=project, tb_client=tb_client)
48
48
 
49
49
  build_failed = False
50
50
  build_error: Optional[str] = None
@@ -90,9 +90,7 @@ def process(
90
90
  click.echo(FeedbackManager.error(message=f"✗ {rebuild_str} failed"))
91
91
  if not watch and exit_on_error:
92
92
  sys_exit("build_error", build_error or "Unknown error")
93
- build_error = build_error or "Unknown error"
94
-
95
- return build_error
93
+ return build_error or "Unknown error"
96
94
 
97
95
  if not silent:
98
96
  if build_result == False: # noqa: E712
@@ -250,7 +248,7 @@ def build_project(
250
248
  if with_connections:
251
249
  echo_dynamodb_local_backfill_feedback(build)
252
250
  return True
253
- elif build_result == "failed":
251
+ if build_result == "failed":
254
252
  error = format_build_errors(result.get("errors", []))
255
253
  else:
256
254
  error = f"Unknown build result. Error: {result.get('error')}"
@@ -614,7 +612,7 @@ def build_vendored_workspaces(project: Project, tb_client: TinyB, config: dict[s
614
612
  click.echo(FeedbackManager.error_exception(error=e))
615
613
 
616
614
 
617
- def build_shared_with_workspaces(project: Project, tb_client: TinyB, config: dict[str, Any]) -> None:
615
+ def build_shared_with_workspaces(project: Project, tb_client: TinyB) -> None:
618
616
  """Scan project for .datasource files and ensure SHARED_WITH workspaces exist."""
619
617
 
620
618
  try:
@@ -18,7 +18,7 @@ from copy import deepcopy
18
18
  from enum import Enum
19
19
  from os import getcwd, getenv
20
20
  from pathlib import Path
21
- from typing import Any, Callable, Dict, Iterable, List, Literal, Optional, Set, Tuple, TypedDict, Union
21
+ from typing import Any, Callable, Dict, Iterable, List, Literal, NoReturn, Optional, Set, Tuple, TypedDict, Union
22
22
  from urllib.parse import urlparse
23
23
 
24
24
  import click
@@ -2370,7 +2370,7 @@ def ask_for_organization(
2370
2370
  event_error_separator = "__error__"
2371
2371
 
2372
2372
 
2373
- def sys_exit(event: str, msg: str) -> None:
2373
+ def sys_exit(event: str, msg: str) -> NoReturn:
2374
2374
  sys.exit(f"{event}{event_error_separator}{msg}")
2375
2375
 
2376
2376
 
@@ -155,16 +155,13 @@ def api_fetch(url: str, headers: dict, request_from: Optional[str] = None) -> di
155
155
  return {}
156
156
 
157
157
 
158
- def _get_classic_workspace_branches(client: TinyB, workspace_id: str) -> list[dict[str, Any]]:
159
- branches: list[dict[str, Any]] = client.user_workspace_branches(version="v0").get("workspaces", [])
160
- return [branch for branch in branches if str(branch.get("main")) == workspace_id]
158
+ def _get_classic_workspace_branches(client: TinyB) -> list[dict[str, Any]]:
159
+ return client.branches(version="v0").get("environments", [])
161
160
 
162
161
 
163
- def _cleanup_classic_migration_blockers(client: TinyB, config: Dict[str, Any]) -> None:
164
- workspace_id = str(config["id"])
165
-
162
+ def _cleanup_classic_migration_blockers(client: TinyB) -> None:
166
163
  try:
167
- branches = _get_classic_workspace_branches(client, workspace_id)
164
+ branches = _get_classic_workspace_branches(client)
168
165
  if not branches:
169
166
  return
170
167
 
@@ -488,7 +485,7 @@ def migrate_to_forward(ctx: click.Context, allow_destructive_operations: bool) -
488
485
  click.echo(FeedbackManager.info(message="Migration cancelled."))
489
486
  return
490
487
 
491
- _cleanup_classic_migration_blockers(client, config)
488
+ _cleanup_classic_migration_blockers(client)
492
489
  _persist_migrate_to_forward_config(project)
493
490
  migrate_to_forward_workspace(client=client, output=output, dry_run=False)
494
491
  create_deployment(