tinybird-cli 5.22.3.dev0__py3-none-any.whl → 6.0.2.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
tinybird/sql_toolset.py CHANGED
@@ -149,12 +149,11 @@ def format_where_for_mutation_command(where_clause: str) -> str:
149
149
  # Functions that take table/dictionary names as string literal arguments.
150
150
  # Normalizing these would cause incorrect cache hits since different table names
151
151
  # would map to the same cache key.
152
- # See: https://clickhouse.com/docs/en/sql-reference/functions/other-functions#joinget
153
- # https://clickhouse.com/docs/en/sql-reference/functions/ext-dict-functions
152
+ # See: https://clickhouse.com/docs/en/sql-reference/functions/ext-dict-functions
154
153
  # https://clickhouse.com/docs/en/sql-reference/table-functions/cluster
155
154
  # https://clickhouse.com/docs/en/sql-reference/table-functions/remote
156
155
  _FUNCTIONS_WITH_TABLE_NAME_ARGS = re.compile(
157
- r"\b(?:joinGet|joinGetOrNull|dictGet\w*|dictHas|dictIsIn|hasColumnInTable|remote|cluster|clusterAllReplicas)\s*\(",
156
+ r"\b(?:dictGet\w*|dictHas|dictIsIn|hasColumnInTable|remote|cluster|clusterAllReplicas)\s*\(",
158
157
  re.IGNORECASE,
159
158
  )
160
159
 
@@ -166,7 +165,7 @@ def _normalize_sql_for_cache(sql: str) -> str:
166
165
  while preserving table/column names, so queries with the same structure share
167
166
  cache entries.
168
167
 
169
- However, some functions like joinGet(), dictGet*, remote(), cluster(), and
168
+ However, some functions like dictGet*, remote(), cluster(), and
170
169
  clusterAllReplicas() take table/dictionary names as arguments. Normalizing these
171
170
  would incorrectly map different tables to the same cache key, so we fall back to
172
171
  using the original SQL for such queries.
@@ -177,8 +176,6 @@ def _normalize_sql_for_cache(sql: str) -> str:
177
176
  'SELECT * FROM events WHERE id = ? AND name = ?'
178
177
  >>> _normalize_sql_for_cache("SELECT * FROM events")
179
178
  'SELECT * FROM events'
180
- >>> _normalize_sql_for_cache("SELECT joinGet('my_table', 'col', id) FROM t")
181
- "SELECT joinGet('my_table', 'col', id) FROM t"
182
179
  >>> _normalize_sql_for_cache("SELECT dictGet('my_dict', 'value', id) FROM t")
183
180
  "SELECT dictGet('my_dict', 'value', id) FROM t"
184
181
  >>> _normalize_sql_for_cache("SELECT * FROM remote('host', db, table)")
@@ -200,7 +197,7 @@ def _normalize_sql_for_cache(sql: str) -> str:
200
197
 
201
198
  # Cache for sql_get_used_tables using normalized SQL as key.
202
199
  # Uses lru-dict (C extension) for a fast LRU implementation.
203
- _sql_get_used_tables_cache: LRU = LRU(2**15)
200
+ _sql_get_used_tables_cache: LRU = LRU(2**13)
204
201
  _sql_get_used_tables_cache_lock = threading.Lock()
205
202
  _sql_get_used_tables_cache_hits = 0
206
203
  _sql_get_used_tables_cache_misses = 0
@@ -395,38 +392,15 @@ class ReplacementsDict(dict):
395
392
  if isinstance(v, tuple):
396
393
  k, r = v
397
394
  if callable(r):
398
- r = update_callable_signature(r)(self.enabled_table_functions)
395
+ r = r(self.enabled_table_functions)
399
396
  super().__setitem__(key, (k, r))
400
397
  return k, r
401
398
  if callable(v):
402
- v = update_callable_signature(v)(self.enabled_table_functions)
399
+ v = v(self.enabled_table_functions)
403
400
  super().__setitem__(key, v)
404
401
  return v
405
402
 
406
403
 
407
- def update_callable_signature(func):
408
- """
409
- Utility function to provide backward compatibility for callable functions
410
- that don't accept the enabled_table_functions parameter.
411
- """
412
- if callable(func):
413
-
414
- def wrapper(enabled_table_functions=None):
415
- # Check if the function accepts the enabled_table_functions parameter
416
- import inspect
417
-
418
- sig = inspect.signature(func)
419
- if len(sig.parameters) == 0:
420
- # Old-style callable with no parameters
421
- return func()
422
- else:
423
- # New-style callable that accepts enabled_table_functions
424
- return func(enabled_table_functions)
425
-
426
- return wrapper
427
- return func
428
-
429
-
430
404
  def tables_or_sql(replacement: dict, table_functions=False, function_allow_list=None) -> set:
431
405
  try:
432
406
  return set(
@@ -13,7 +13,6 @@ from tinybird.config import get_display_host
13
13
  from tinybird.feedback_manager import FeedbackManager
14
14
  from tinybird.tb_cli_modules.cli import cli
15
15
  from tinybird.tb_cli_modules.common import (
16
- configure_connector,
17
16
  coro,
18
17
  echo_safe_humanfriendly_tables_format_smart_table,
19
18
  get_host_from_region,
@@ -35,11 +34,6 @@ from tinybird.tb_cli_modules.regions import Region
35
34
  @click.option(
36
35
  "--region", envvar="TB_REGION", help="Set region. Run 'tb auth ls' to show available regions. Overrides host."
37
36
  )
38
- @click.option(
39
- "--connector",
40
- type=click.Choice(["bigquery", "snowflake"], case_sensitive=True),
41
- help="Set credentials for one of the supported connectors",
42
- )
43
37
  @click.option(
44
38
  "-i",
45
39
  "--interactive",
@@ -49,7 +43,7 @@ from tinybird.tb_cli_modules.regions import Region
49
43
  )
50
44
  @click.pass_context
51
45
  @coro
52
- async def auth(ctx: click.Context, token: str, host: str, region: str, connector: str, interactive: bool) -> None:
46
+ async def auth(ctx: click.Context, token: str, host: str, region: str, interactive: bool) -> None:
53
47
  """Configure auth."""
54
48
 
55
49
  config: CLIConfig = CLIConfig.get_project_config()
@@ -58,10 +52,6 @@ async def auth(ctx: click.Context, token: str, host: str, region: str, connector
58
52
  if host:
59
53
  config.set_host(host)
60
54
 
61
- if connector:
62
- await configure_connector(connector)
63
- return
64
-
65
55
  # Only run when doing a bare 'tb auth'
66
56
  if ctx.invoked_subcommand:
67
57
  return
@@ -27,7 +27,7 @@ from tinybird.client import (
27
27
  OperationCanNotBePerformed,
28
28
  TinyB,
29
29
  )
30
- from tinybird.config import CURRENT_VERSION, SUPPORTED_CONNECTORS, VERSION, FeatureFlags, get_config
30
+ from tinybird.config import CURRENT_VERSION, VERSION, FeatureFlags, get_config
31
31
  from tinybird.datafile_common import (
32
32
  AlreadyExistsException,
33
33
  CLIGitRelease,
@@ -62,7 +62,6 @@ from tinybird.tb_cli_modules.common import (
62
62
  getenv_bool,
63
63
  is_major_semver,
64
64
  is_post_semver,
65
- load_connector_config,
66
65
  remove_release,
67
66
  try_update_config_with_remote,
68
67
  )
@@ -85,32 +84,6 @@ DEFAULT_PATTERNS: List[Tuple[str, Union[str, Callable[[str], str]]]] = [
85
84
  @click.option("--token", help="Use auth token, defaults to TB_TOKEN envvar, then to the .tinyb file")
86
85
  @click.option("--host", help="Use custom host, defaults to TB_HOST envvar, then to https://api.tinybird.co")
87
86
  @click.option("--semver", help="Semver of a Release to run the command. Example: 1.0.0", hidden=True)
88
- @click.option("--gcp-project-id", help="The Google Cloud project ID", hidden=True)
89
- @click.option(
90
- "--gcs-bucket", help="The Google Cloud Storage bucket to write temp files when using the connectors", hidden=True
91
- )
92
- @click.option(
93
- "--google-application-credentials",
94
- envvar="GOOGLE_APPLICATION_CREDENTIALS",
95
- help="Set GOOGLE_APPLICATION_CREDENTIALS",
96
- hidden=True,
97
- )
98
- @click.option("--sf-account", help="The Snowflake Account (e.g. your-domain.west-europe.azure)", hidden=True)
99
- @click.option("--sf-warehouse", help="The Snowflake warehouse name", hidden=True)
100
- @click.option("--sf-database", help="The Snowflake database name", hidden=True)
101
- @click.option("--sf-schema", help="The Snowflake schema name", hidden=True)
102
- @click.option("--sf-role", help="The Snowflake role name", hidden=True)
103
- @click.option("--sf-user", help="The Snowflake user name", hidden=True)
104
- @click.option("--sf-password", help="The Snowflake password", hidden=True)
105
- @click.option(
106
- "--sf-storage-integration",
107
- help="The Snowflake GCS storage integration name (leave empty to auto-generate one)",
108
- hidden=True,
109
- )
110
- @click.option("--sf-stage", help="The Snowflake GCS stage name (leave empty to auto-generate one)", hidden=True)
111
- @click.option(
112
- "--with-headers", help="Flag to enable connector to export with headers", is_flag=True, default=False, hidden=True
113
- )
114
87
  @click.option(
115
88
  "--version-warning/--no-version-warning",
116
89
  envvar="TB_VERSION_WARNING",
@@ -127,19 +100,6 @@ async def cli(
127
100
  token: str,
128
101
  host: str,
129
102
  semver: str,
130
- gcp_project_id: str,
131
- gcs_bucket: str,
132
- google_application_credentials: str,
133
- sf_account: str,
134
- sf_warehouse: str,
135
- sf_database: str,
136
- sf_schema: str,
137
- sf_role: str,
138
- sf_user: str,
139
- sf_password: str,
140
- sf_storage_integration: str,
141
- sf_stage,
142
- with_headers: bool,
143
103
  version_warning: bool,
144
104
  show_tokens: bool,
145
105
  ) -> None:
@@ -212,52 +172,10 @@ async def cli(
212
172
  if ctx.invoked_subcommand == "auth":
213
173
  return
214
174
 
215
- from tinybird.connectors import create_connector
216
-
217
- if gcp_project_id and gcs_bucket and google_application_credentials and not sf_account:
218
- bq_config = {
219
- "project_id": gcp_project_id,
220
- "bucket_name": gcs_bucket,
221
- "service_account": google_application_credentials,
222
- "with_headers": with_headers,
223
- }
224
- ctx.ensure_object(dict)["bigquery"] = create_connector("bigquery", bq_config)
225
- if (
226
- sf_account
227
- and sf_warehouse
228
- and sf_database
229
- and sf_schema
230
- and sf_role
231
- and sf_user
232
- and sf_password
233
- and gcs_bucket
234
- and google_application_credentials
235
- and gcp_project_id
236
- ):
237
- sf_config = {
238
- "account": sf_account,
239
- "warehouse": sf_warehouse,
240
- "database": sf_database,
241
- "schema": sf_schema,
242
- "role": sf_role,
243
- "user": sf_user,
244
- "password": sf_password,
245
- "storage_integration": sf_storage_integration,
246
- "stage": sf_stage,
247
- "bucket_name": gcs_bucket,
248
- "service_account": google_application_credentials,
249
- "project_id": gcp_project_id,
250
- "with_headers": with_headers,
251
- }
252
- ctx.ensure_object(dict)["snowflake"] = create_connector("snowflake", sf_config)
253
-
254
175
  logging.debug("debug enabled")
255
176
 
256
177
  ctx.ensure_object(dict)["client"] = _get_tb_client(config.get("token", None), config["host"], semver) # type: ignore[arg-type]
257
178
 
258
- for connector in SUPPORTED_CONNECTORS:
259
- load_connector_config(ctx, connector, debug, check_uninstalled=True)
260
-
261
179
 
262
180
  @cli.command()
263
181
  @click.option(
@@ -16,9 +16,9 @@ from contextlib import closing
16
16
  from copy import deepcopy
17
17
  from enum import Enum
18
18
  from functools import wraps
19
- from os import chmod, environ, getcwd, getenv
19
+ from os import chmod, getcwd, getenv
20
20
  from pathlib import Path
21
- from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Literal, Optional, Set, Tuple, TypedDict, Union
21
+ from typing import Any, Callable, Dict, Iterable, List, Literal, Optional, Set, Tuple, TypedDict, Union
22
22
  from urllib.parse import urlparse
23
23
 
24
24
  import aiofiles
@@ -35,7 +35,6 @@ from packaging.version import Version
35
35
  from tinybird.client import (
36
36
  AuthException,
37
37
  AuthNoTokenException,
38
- ConnectorNothingToLoad,
39
38
  DoesNotExistException,
40
39
  JobException,
41
40
  OperationCanNotBePerformed,
@@ -46,17 +45,11 @@ from tinybird.config import (
46
45
  DEFAULT_UI_HOST,
47
46
  DEPRECATED_PROJECT_PATHS,
48
47
  PROJECT_PATHS,
49
- SUPPORTED_CONNECTORS,
50
48
  VERSION,
51
49
  FeatureFlags,
52
50
  get_config,
53
51
  get_display_host,
54
- write_config,
55
52
  )
56
-
57
- if TYPE_CHECKING:
58
- from tinybird.connectors import Connector
59
-
60
53
  from tinybird.feedback_manager import FeedbackManager, warning_message
61
54
  from tinybird.git_settings import DEFAULT_TINYENV_FILE
62
55
  from tinybird.syncasync import async_to_sync
@@ -78,6 +71,9 @@ from tinybird.tb_cli_modules.telemetry import (
78
71
  is_ci_environment,
79
72
  )
80
73
 
74
+ # Pre-compiled regex pattern for name normalization
75
+ _PATTERN_NORMALIZE_NAME = re.compile(r"[^0-9a-zA-Z_]")
76
+
81
77
  SUPPORTED_FORMATS = ["csv", "ndjson", "json", "parquet"]
82
78
  OLDEST_ROLLBACK = "oldest_rollback"
83
79
  MAIN_BRANCH = "main"
@@ -89,16 +85,6 @@ def obfuscate_token(value: Optional[str]) -> Optional[str]:
89
85
  return f"{value[:4]}...{value[-8:]}"
90
86
 
91
87
 
92
- def create_connector(connector: str, options: Dict[str, Any]):
93
- # Imported here to improve startup time when the connectors aren't used
94
- from tinybird.connectors import UNINSTALLED_CONNECTORS
95
- from tinybird.connectors import create_connector as _create_connector
96
-
97
- if connector in UNINSTALLED_CONNECTORS:
98
- raise CLIException(FeedbackManager.error_connector_not_installed(connector=connector))
99
- return _create_connector(connector, options)
100
-
101
-
102
88
  def coro(f):
103
89
  @wraps(f)
104
90
  def wrapper(*args, **kwargs):
@@ -135,7 +121,7 @@ def echo_safe_humanfriendly_tables_format_smart_table(data: Iterable[Any], colum
135
121
 
136
122
 
137
123
  def normalize_datasource_name(s: str) -> str:
138
- s = re.sub(r"[^0-9a-zA-Z_]", "_", s)
124
+ s = _PATTERN_NORMALIZE_NAME.sub("_", s)
139
125
  if s[0] in "0123456789":
140
126
  return "c_" + s
141
127
  return s
@@ -269,24 +255,6 @@ variable to '1' or 'true'."""
269
255
  sys.exit(exit_code)
270
256
 
271
257
 
272
- def load_connector_config(ctx: Context, connector_name: str, debug: bool, check_uninstalled: bool = False):
273
- config_file = Path(getcwd()) / f".tinyb_{connector_name}"
274
- try:
275
- if connector_name not in ctx.ensure_object(dict):
276
- with open(config_file) as file:
277
- config = json.loads(file.read())
278
- from tinybird.connectors import UNINSTALLED_CONNECTORS
279
-
280
- if check_uninstalled and connector_name in UNINSTALLED_CONNECTORS:
281
- click.echo(FeedbackManager.warning_connector_not_installed(connector=connector_name))
282
- return
283
- ctx.ensure_object(dict)[connector_name] = create_connector(connector_name, config)
284
- except OSError:
285
- if debug:
286
- click.echo(f"** {connector_name} connector not configured")
287
- pass
288
-
289
-
290
258
  def getenv_bool(key: str, default: bool) -> bool:
291
259
  v: Optional[str] = getenv(key)
292
260
  if v is None:
@@ -306,31 +274,26 @@ def create_tb_client(ctx: Context) -> TinyB:
306
274
  return _get_tb_client(token, host, semver=semver)
307
275
 
308
276
 
309
- async def _analyze(filename: str, client: TinyB, format: str, connector: Optional["Connector"] = None):
277
+ async def _analyze(filename: str, client: TinyB, format: str):
310
278
  data: Optional[bytes] = None
311
- if not connector:
312
- parsed = urlparse(filename)
313
- if parsed.scheme in ("http", "https"):
314
- meta = await client.datasource_analyze(filename)
315
- else:
316
- async with aiofiles.open(filename, "rb") as file:
317
- # We need to read the whole file in binary for Parquet, while for the
318
- # others we just read 1KiB
319
- if format == "parquet":
320
- data = await file.read()
321
- else:
322
- data = await file.read(1024 * 1024)
323
-
324
- meta = await client.datasource_analyze_file(data)
279
+ parsed = urlparse(filename)
280
+ if parsed.scheme in ("http", "https"):
281
+ meta = await client.datasource_analyze(filename)
325
282
  else:
326
- meta = connector.datasource_analyze(filename)
283
+ async with aiofiles.open(filename, "rb") as file:
284
+ # We need to read the whole file in binary for Parquet, while for the
285
+ # others we just read 1KiB
286
+ if format == "parquet":
287
+ data = await file.read()
288
+ else:
289
+ data = await file.read(1024 * 1024)
290
+
291
+ meta = await client.datasource_analyze_file(data)
327
292
  return meta, data
328
293
 
329
294
 
330
- async def _generate_datafile(
331
- filename: str, client: TinyB, format: str, connector: Optional["Connector"] = None, force: Optional[bool] = False
332
- ):
333
- meta, data = await _analyze(filename, client, format, connector=connector)
295
+ async def _generate_datafile(filename: str, client: TinyB, format: str, force: Optional[bool] = False):
296
+ meta, data = await _analyze(filename, client, format)
334
297
  schema = meta["analysis"]["schema"]
335
298
  schema = schema.replace(", ", ",\n ")
336
299
  datafile = f"""DESCRIPTION >\n Generated from {filename}\n\nSCHEMA >\n {schema}"""
@@ -465,77 +428,12 @@ async def folder_init(
465
428
  )
466
429
 
467
430
 
468
- async def configure_connector(connector):
469
- if connector not in SUPPORTED_CONNECTORS:
470
- raise CLIException(FeedbackManager.error_invalid_connector(connectors=", ".join(SUPPORTED_CONNECTORS)))
471
-
472
- file_name = f".tinyb_{connector}"
473
- config_file = Path(getcwd()) / file_name
474
- if connector == "bigquery":
475
- project = click.prompt("BigQuery project ID")
476
- service_account = click.prompt(
477
- "Path to a JSON service account file with permissions to export from BigQuery, write in Storage and sign URLs (leave empty to use GOOGLE_APPLICATION_CREDENTIALS environment variable)",
478
- default=environ.get("GOOGLE_APPLICATION_CREDENTIALS", ""),
479
- )
480
- bucket_name = click.prompt("Name of a Google Cloud Storage bucket to store temporary exported files")
481
-
482
- try:
483
- config = {"project_id": project, "service_account": service_account, "bucket_name": bucket_name}
484
- await write_config(config, file_name)
485
- except Exception:
486
- raise CLIException(FeedbackManager.error_file_config(config_file=config_file))
487
- elif connector == "snowflake":
488
- sf_account = click.prompt("Snowflake Account (e.g. your-domain.west-europe.azure)")
489
- sf_warehouse = click.prompt("Snowflake warehouse name")
490
- sf_database = click.prompt("Snowflake database name")
491
- sf_schema = click.prompt("Snowflake schema name")
492
- sf_role = click.prompt("Snowflake role name")
493
- sf_user = click.prompt("Snowflake user name")
494
- sf_password = click.prompt("Snowflake password")
495
- sf_storage_integration = click.prompt(
496
- "Snowflake GCS storage integration name (leave empty to auto-generate one)", default=""
497
- )
498
- sf_stage = click.prompt("Snowflake GCS stage name (leave empty to auto-generate one)", default="")
499
- project = click.prompt("Google Cloud project ID to store temporary files")
500
- service_account = click.prompt(
501
- "Path to a JSON service account file with permissions to write in Storagem, sign URLs and IAM (leave empty to use GOOGLE_APPLICATION_CREDENTIALS environment variable)",
502
- default=environ.get("GOOGLE_APPLICATION_CREDENTIALS", ""),
503
- )
504
- bucket_name = click.prompt("Name of a Google Cloud Storage bucket to store temporary exported files")
505
-
506
- if not service_account:
507
- service_account = getenv("GOOGLE_APPLICATION_CREDENTIALS")
508
-
509
- try:
510
- config = {
511
- "account": sf_account,
512
- "warehouse": sf_warehouse,
513
- "database": sf_database,
514
- "schema": sf_schema,
515
- "role": sf_role,
516
- "user": sf_user,
517
- "password": sf_password,
518
- "storage_integration": sf_storage_integration,
519
- "stage": sf_stage,
520
- "service_account": service_account,
521
- "bucket_name": bucket_name,
522
- "project_id": project,
523
- }
524
- await write_config(config, file_name)
525
- except Exception:
526
- raise CLIException(FeedbackManager.error_file_config(config_file=config_file))
527
-
528
- click.echo(FeedbackManager.success_connector_config(connector=connector, file_name=file_name))
529
-
530
-
531
431
  def _compare_region_host(region_name_or_host: str, region: Dict[str, Any]) -> bool:
532
432
  if region["name"].lower() == region_name_or_host:
533
433
  return True
534
434
  if region["host"] == region_name_or_host:
535
435
  return True
536
- if region["api_host"] == region_name_or_host:
537
- return True
538
- return False
436
+ return region["api_host"] == region_name_or_host
539
437
 
540
438
 
541
439
  def ask_for_region_interactively(regions):
@@ -1071,33 +969,17 @@ async def push_data(
1071
969
  ctx: Context,
1072
970
  datasource_name: str,
1073
971
  url,
1074
- connector: Optional[str],
1075
- sql: Optional[str],
1076
972
  mode: str = "append",
1077
973
  sql_condition: Optional[str] = None,
1078
974
  replace_options=None,
1079
- ignore_empty: bool = False,
1080
975
  concurrency: int = 1,
1081
976
  ):
1082
977
  if url and type(url) is tuple:
1083
978
  url = url[0]
1084
979
  client: TinyB = ctx.obj["client"]
1085
980
 
1086
- if connector and sql:
1087
- load_connector_config(ctx, connector, False, check_uninstalled=False)
1088
- if connector not in ctx.obj:
1089
- raise CLIException(FeedbackManager.error_connector_not_configured(connector=connector))
1090
- else:
1091
- _connector: Connector = ctx.obj[connector]
1092
- click.echo(FeedbackManager.info_starting_export_process(connector=connector))
1093
- try:
1094
- url = _connector.export_to_gcs(sql, datasource_name, mode)
1095
- except ConnectorNothingToLoad as e:
1096
- if ignore_empty:
1097
- click.echo(str(e))
1098
- return
1099
- else:
1100
- raise e
981
+ if not url:
982
+ raise CLIException(FeedbackManager.error_missing_url(datasource=datasource_name))
1101
983
 
1102
984
  def cb(res):
1103
985
  if cb.First: # type: ignore[attr-defined]
@@ -1199,19 +1081,13 @@ async def push_data(
1199
1081
  else:
1200
1082
  click.echo(FeedbackManager.success_appended_datasource(datasource=datasource_name))
1201
1083
  click.echo(FeedbackManager.info_data_pushed(datasource=datasource_name))
1202
- finally:
1203
- try:
1204
- for url in urls:
1205
- _connector.clean(urlparse(url).path.split("/")[-1])
1206
- except Exception:
1207
- pass
1208
1084
 
1209
1085
 
1210
1086
  async def sync_data(ctx, datasource_name: str, yes: bool):
1211
1087
  client: TinyB = ctx.obj["client"]
1212
1088
  datasource = await client.get_datasource(datasource_name)
1213
1089
 
1214
- VALID_DATASOURCES = ["bigquery", "snowflake", "s3", "s3_iamrole", "gcs"]
1090
+ VALID_DATASOURCES = ["s3", "s3_iamrole", "gcs"]
1215
1091
  if datasource["type"] not in VALID_DATASOURCES:
1216
1092
  raise CLIException(FeedbackManager.error_sync_not_supported(valid_datasources=VALID_DATASOURCES))
1217
1093
 
@@ -1296,7 +1172,7 @@ def validate_kafka_bootstrap_servers(bootstrap_servers):
1296
1172
  try:
1297
1173
  sock.settimeout(3)
1298
1174
  sock.connect((host, port))
1299
- except socket.timeout:
1175
+ except TimeoutError:
1300
1176
  raise CLIException(FeedbackManager.error_kafka_bootstrap_server_conn_timeout())
1301
1177
  except Exception:
1302
1178
  raise CLIException(FeedbackManager.error_kafka_bootstrap_server_conn())
@@ -2022,7 +1898,7 @@ async def validate_aws_iamrole_connection_name(
2022
1898
  client: TinyB, connection_name: Optional[str], no_validate: Optional[bool] = False
2023
1899
  ) -> str:
2024
1900
  if connection_name and no_validate is False:
2025
- if await client.get_connector(connection_name, skip_bigquery=True) is not None:
1901
+ if await client.get_connector(connection_name) is not None:
2026
1902
  raise CLIConnectionException(FeedbackManager.info_connection_already_exists(name=connection_name))
2027
1903
  else:
2028
1904
  while not connection_name:
@@ -2039,8 +1915,6 @@ async def validate_aws_iamrole_connection_name(
2039
1915
  class DataConnectorType(str, Enum):
2040
1916
  KAFKA = "kafka"
2041
1917
  GCLOUD_SCHEDULER = "gcscheduler"
2042
- SNOWFLAKE = "snowflake"
2043
- BIGQUERY = "bigquery"
2044
1918
  GCLOUD_STORAGE = "gcs"
2045
1919
  GCLOUD_STORAGE_HMAC = "gcs_hmac"
2046
1920
  GCLOUD_STORAGE_SA = "gcs_service_account"
@@ -31,9 +31,7 @@ class FeatureFlags:
31
31
  def send_telemetry(cls) -> bool:
32
32
  if os.environ.get("TB_CLI_TELEMETRY_OPTOUT", "0") == "1":
33
33
  return False
34
- if "x.y.z" in CURRENT_VERSION and os.environ.get("TB_CLI_TELEMETRY_SEND_IN_LOCAL", "0") == "0":
35
- return False
36
- return True
34
+ return not ("x.y.z" in CURRENT_VERSION and os.environ.get("TB_CLI_TELEMETRY_SEND_IN_LOCAL", "0") == "0")
37
35
 
38
36
 
39
37
  def compare_versions(a: str, b: str) -> int: