databricks-sql-connector 4.2.1__tar.gz → 4.2.2__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 (69) hide show
  1. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/CHANGELOG.md +7 -0
  2. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/PKG-INFO +3 -2
  3. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/README.md +1 -1
  4. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/pyproject.toml +6 -2
  5. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/__init__.py +1 -1
  6. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/auth/common.py +2 -0
  7. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/sea/backend.py +1 -1
  8. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/thrift_backend.py +34 -38
  9. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/client.py +35 -3
  10. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/common/feature_flag.py +5 -3
  11. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/common/unified_http_client.py +46 -1
  12. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/exc.py +33 -4
  13. databricks_sql_connector-4.2.2/src/databricks/sql/telemetry/circuit_breaker_manager.py +112 -0
  14. databricks_sql_connector-4.2.2/src/databricks/sql/telemetry/latency_logger.py +220 -0
  15. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/telemetry/telemetry_client.py +215 -61
  16. databricks_sql_connector-4.2.2/src/databricks/sql/telemetry/telemetry_push_client.py +201 -0
  17. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/utils.py +3 -0
  18. databricks_sql_connector-4.2.1/src/databricks/sql/telemetry/latency_logger.py +0 -216
  19. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/LICENSE +0 -0
  20. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/__init__.py +0 -0
  21. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/auth/__init__.py +0 -0
  22. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/auth/auth.py +0 -0
  23. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/auth/auth_utils.py +0 -0
  24. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/auth/authenticators.py +0 -0
  25. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/auth/endpoint.py +0 -0
  26. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/auth/oauth.py +0 -0
  27. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/auth/oauth_http_handler.py +0 -0
  28. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/auth/retry.py +0 -0
  29. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/auth/thrift_http_client.py +0 -0
  30. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/auth/token_federation.py +0 -0
  31. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/databricks_client.py +0 -0
  32. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/sea/models/__init__.py +0 -0
  33. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/sea/models/base.py +0 -0
  34. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/sea/models/requests.py +0 -0
  35. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/sea/models/responses.py +0 -0
  36. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/sea/queue.py +0 -0
  37. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/sea/result_set.py +0 -0
  38. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/sea/utils/constants.py +0 -0
  39. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/sea/utils/conversion.py +0 -0
  40. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/sea/utils/filters.py +0 -0
  41. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/sea/utils/http_client.py +0 -0
  42. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/sea/utils/normalize.py +0 -0
  43. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/types.py +0 -0
  44. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/utils/__init__.py +0 -0
  45. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/backend/utils/guid_utils.py +0 -0
  46. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/cloudfetch/download_manager.py +0 -0
  47. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/cloudfetch/downloader.py +0 -0
  48. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/common/http.py +0 -0
  49. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/common/http_utils.py +0 -0
  50. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/experimental/__init__.py +0 -0
  51. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/experimental/oauth_persistence.py +0 -0
  52. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/parameters/__init__.py +0 -0
  53. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/parameters/native.py +0 -0
  54. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/parameters/py.typed +0 -0
  55. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/py.typed +0 -0
  56. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/result_set.py +0 -0
  57. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/session.py +0 -0
  58. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/telemetry/models/endpoint_models.py +0 -0
  59. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/telemetry/models/enums.py +0 -0
  60. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/telemetry/models/event.py +0 -0
  61. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/telemetry/models/frontend_logs.py +0 -0
  62. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/telemetry/utils.py +0 -0
  63. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/thrift_api/TCLIService/TCLIService-remote +0 -0
  64. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/thrift_api/TCLIService/TCLIService.py +0 -0
  65. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/thrift_api/TCLIService/__init__.py +0 -0
  66. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/thrift_api/TCLIService/constants.py +0 -0
  67. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/thrift_api/TCLIService/ttypes.py +0 -0
  68. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/thrift_api/__init__.py +0 -0
  69. {databricks_sql_connector-4.2.1 → databricks_sql_connector-4.2.2}/src/databricks/sql/types.py +0 -0
@@ -1,5 +1,12 @@
1
1
  # Release History
2
2
 
3
+ # 4.2.2 (2025-12-01)
4
+ - Change default use_hybrid_disposition to False (databricks/databricks-sql-python#714 by @samikshya-db)
5
+ - Circuit breaker changes using pybreaker (databricks/databricks-sql-python#705 by @nikhilsuri-db)
6
+ - perf: Optimize telemetry latency logging to reduce overhead (databricks/databricks-sql-python#715 by @samikshya-db)
7
+ - basic e2e test for force telemetry verification (databricks/databricks-sql-python#708 by @nikhilsuri-db)
8
+ - Telemetry is ON by default to track connection stats. (Note : This strictly excludes PII, query text, and results) (databricks/databricks-sql-python#717 by @samikshya-db)
9
+
3
10
  # 4.2.1 (2025-11-20)
4
11
  - Ignore transactions by default (databricks/databricks-sql-python#711 by @jayantsing-db)
5
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: databricks-sql-connector
3
- Version: 4.2.1
3
+ Version: 4.2.2
4
4
  Summary: Databricks SQL Connector for Python
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -24,6 +24,7 @@ Requires-Dist: pandas (>=1.2.5,<2.3.0) ; python_version >= "3.8" and python_vers
24
24
  Requires-Dist: pandas (>=2.2.3,<2.3.0) ; python_version >= "3.13"
25
25
  Requires-Dist: pyarrow (>=14.0.1) ; (python_version >= "3.8" and python_version < "3.13") and (extra == "pyarrow")
26
26
  Requires-Dist: pyarrow (>=18.0.0) ; (python_version >= "3.13") and (extra == "pyarrow")
27
+ Requires-Dist: pybreaker (>=1.0.0,<2.0.0)
27
28
  Requires-Dist: pyjwt (>=2.0.0,<3.0.0)
28
29
  Requires-Dist: python-dateutil (>=2.8.0,<3.0.0)
29
30
  Requires-Dist: requests (>=2.18.1,<3.0.0)
@@ -48,7 +49,7 @@ You are welcome to file an issue here for general use cases. You can also contac
48
49
 
49
50
  ## Requirements
50
51
 
51
- Python 3.8 or above is required.
52
+ Python 3.9 or above is required.
52
53
 
53
54
  ## Documentation
54
55
 
@@ -13,7 +13,7 @@ You are welcome to file an issue here for general use cases. You can also contac
13
13
 
14
14
  ## Requirements
15
15
 
16
- Python 3.8 or above is required.
16
+ Python 3.9 or above is required.
17
17
 
18
18
  ## Documentation
19
19
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "databricks-sql-connector"
3
- version = "4.2.1"
3
+ version = "4.2.2"
4
4
  description = "Databricks SQL Connector for Python"
5
5
  authors = ["Databricks <databricks-sql-connector-maintainers@databricks.com>"]
6
6
  license = "Apache-2.0"
@@ -26,6 +26,7 @@ pyarrow = [
26
26
  { version = ">=18.0.0", python = ">=3.13", optional=true }
27
27
  ]
28
28
  pyjwt = "^2.0.0"
29
+ pybreaker = "^1.0.0"
29
30
  requests-kerberos = {version = "^0.15.0", optional = true}
30
31
 
31
32
 
@@ -61,7 +62,10 @@ exclude = ['ttypes\.py$', 'TCLIService\.py$']
61
62
  exclude = '/(\.eggs|\.git|\.hg|\.mypy_cache|\.nox|\.tox|\.venv|\.svn|_build|buck-out|build|dist|thrift_api)/'
62
63
 
63
64
  [tool.pytest.ini_options]
64
- markers = {"reviewed" = "Test case has been reviewed by Databricks"}
65
+ markers = [
66
+ "reviewed: Test case has been reviewed by Databricks",
67
+ "serial: Tests that must run serially (not parallelized)"
68
+ ]
65
69
  minversion = "6.0"
66
70
  log_cli = "false"
67
71
  log_cli_level = "INFO"
@@ -71,7 +71,7 @@ DATETIME = DBAPITypeObject("timestamp")
71
71
  DATE = DBAPITypeObject("date")
72
72
  ROWID = DBAPITypeObject()
73
73
 
74
- __version__ = "4.2.1"
74
+ __version__ = "4.2.2"
75
75
  USER_AGENT_NAME = "PyDatabricksSqlConnector"
76
76
 
77
77
  # These two functions are pyhive legacy
@@ -51,6 +51,7 @@ class ClientContext:
51
51
  pool_connections: Optional[int] = None,
52
52
  pool_maxsize: Optional[int] = None,
53
53
  user_agent: Optional[str] = None,
54
+ telemetry_circuit_breaker_enabled: Optional[bool] = True,
54
55
  ):
55
56
  self.hostname = hostname
56
57
  self.access_token = access_token
@@ -83,6 +84,7 @@ class ClientContext:
83
84
  self.pool_connections = pool_connections or 10
84
85
  self.pool_maxsize = pool_maxsize or 20
85
86
  self.user_agent = user_agent
87
+ self.telemetry_circuit_breaker_enabled = bool(telemetry_circuit_breaker_enabled)
86
88
 
87
89
 
88
90
  def get_effective_azure_login_app_id(hostname) -> str:
@@ -157,7 +157,7 @@ class SeaDatabricksClient(DatabricksClient):
157
157
  "_use_arrow_native_complex_types", True
158
158
  )
159
159
 
160
- self.use_hybrid_disposition = kwargs.get("use_hybrid_disposition", True)
160
+ self.use_hybrid_disposition = kwargs.get("use_hybrid_disposition", False)
161
161
  self.use_cloud_fetch = kwargs.get("use_cloud_fetch", True)
162
162
 
163
163
  # Extract warehouse ID from http_path
@@ -163,6 +163,7 @@ class ThriftDatabricksClient(DatabricksClient):
163
163
  else:
164
164
  raise ValueError("No valid connection settings.")
165
165
 
166
+ self._host = server_hostname
166
167
  self._initialize_retry_args(kwargs)
167
168
  self._use_arrow_native_complex_types = kwargs.get(
168
169
  "_use_arrow_native_complex_types", True
@@ -279,14 +280,14 @@ class ThriftDatabricksClient(DatabricksClient):
279
280
  )
280
281
 
281
282
  @staticmethod
282
- def _check_response_for_error(response, session_id_hex=None):
283
+ def _check_response_for_error(response, host_url=None):
283
284
  if response.status and response.status.statusCode in [
284
285
  ttypes.TStatusCode.ERROR_STATUS,
285
286
  ttypes.TStatusCode.INVALID_HANDLE_STATUS,
286
287
  ]:
287
288
  raise DatabaseError(
288
289
  response.status.errorMessage,
289
- session_id_hex=session_id_hex,
290
+ host_url=host_url,
290
291
  )
291
292
 
292
293
  @staticmethod
@@ -340,7 +341,7 @@ class ThriftDatabricksClient(DatabricksClient):
340
341
  network_request_error = RequestError(
341
342
  user_friendly_error_message,
342
343
  full_error_info_context,
343
- self._session_id_hex,
344
+ self._host,
344
345
  error_info.error,
345
346
  )
346
347
  logger.info(network_request_error.message_with_context())
@@ -461,13 +462,12 @@ class ThriftDatabricksClient(DatabricksClient):
461
462
  errno.ECONNRESET, # | 104 | 54 |
462
463
  errno.ETIMEDOUT, # | 110 | 60 |
463
464
  ]
465
+ # fmt: on
464
466
 
465
467
  gos_name = TCLIServiceClient.GetOperationStatus.__name__
466
468
  # retry on timeout. Happens a lot in Azure and it is safe as data has not been sent to server yet
467
469
  if method.__name__ == gos_name or err.errno == errno.ETIMEDOUT:
468
470
  retry_delay = bound_retry_delay(attempt, self._retry_delay_default)
469
-
470
- # fmt: on
471
471
  log_string = f"{gos_name} failed with code {err.errno} and will attempt to retry"
472
472
  if err.errno in info_errs:
473
473
  logger.info(log_string)
@@ -516,9 +516,7 @@ class ThriftDatabricksClient(DatabricksClient):
516
516
  if not isinstance(response_or_error_info, RequestErrorInfo):
517
517
  # log nothing here, presume that main request logging covers
518
518
  response = response_or_error_info
519
- ThriftDatabricksClient._check_response_for_error(
520
- response, self._session_id_hex
521
- )
519
+ ThriftDatabricksClient._check_response_for_error(response, self._host)
522
520
  return response
523
521
 
524
522
  error_info = response_or_error_info
@@ -533,7 +531,7 @@ class ThriftDatabricksClient(DatabricksClient):
533
531
  "Error: expected server to use a protocol version >= "
534
532
  "SPARK_CLI_SERVICE_PROTOCOL_V2, "
535
533
  "instead got: {}".format(protocol_version),
536
- session_id_hex=self._session_id_hex,
534
+ host_url=self._host,
537
535
  )
538
536
 
539
537
  def _check_initial_namespace(self, catalog, schema, response):
@@ -547,7 +545,7 @@ class ThriftDatabricksClient(DatabricksClient):
547
545
  raise InvalidServerResponseError(
548
546
  "Setting initial namespace not supported by the DBR version, "
549
547
  "Please use a Databricks SQL endpoint or a cluster with DBR >= 9.0.",
550
- session_id_hex=self._session_id_hex,
548
+ host_url=self._host,
551
549
  )
552
550
 
553
551
  if catalog:
@@ -555,7 +553,7 @@ class ThriftDatabricksClient(DatabricksClient):
555
553
  raise InvalidServerResponseError(
556
554
  "Unexpected response from server: Trying to set initial catalog to {}, "
557
555
  + "but server does not support multiple catalogs.".format(catalog), # type: ignore
558
- session_id_hex=self._session_id_hex,
556
+ host_url=self._host,
559
557
  )
560
558
 
561
559
  def _check_session_configuration(self, session_configuration):
@@ -570,7 +568,7 @@ class ThriftDatabricksClient(DatabricksClient):
570
568
  TIMESTAMP_AS_STRING_CONFIG,
571
569
  session_configuration[TIMESTAMP_AS_STRING_CONFIG],
572
570
  ),
573
- session_id_hex=self._session_id_hex,
571
+ host_url=self._host,
574
572
  )
575
573
 
576
574
  def open_session(self, session_configuration, catalog, schema) -> SessionId:
@@ -639,7 +637,7 @@ class ThriftDatabricksClient(DatabricksClient):
639
637
  and guid_to_hex_id(op_handle.operationId.guid),
640
638
  "diagnostic-info": get_operations_resp.diagnosticInfo,
641
639
  },
642
- session_id_hex=self._session_id_hex,
640
+ host_url=self._host,
643
641
  )
644
642
  else:
645
643
  raise ServerOperationError(
@@ -649,7 +647,7 @@ class ThriftDatabricksClient(DatabricksClient):
649
647
  and guid_to_hex_id(op_handle.operationId.guid),
650
648
  "diagnostic-info": None,
651
649
  },
652
- session_id_hex=self._session_id_hex,
650
+ host_url=self._host,
653
651
  )
654
652
  elif get_operations_resp.operationState == ttypes.TOperationState.CLOSED_STATE:
655
653
  raise DatabaseError(
@@ -660,7 +658,7 @@ class ThriftDatabricksClient(DatabricksClient):
660
658
  "operation-id": op_handle
661
659
  and guid_to_hex_id(op_handle.operationId.guid)
662
660
  },
663
- session_id_hex=self._session_id_hex,
661
+ host_url=self._host,
664
662
  )
665
663
 
666
664
  def _poll_for_status(self, op_handle):
@@ -683,7 +681,7 @@ class ThriftDatabricksClient(DatabricksClient):
683
681
  else:
684
682
  raise OperationalError(
685
683
  "Unsupported TRowSet instance {}".format(t_row_set),
686
- session_id_hex=self._session_id_hex,
684
+ host_url=self._host,
687
685
  )
688
686
  return convert_decimals_in_arrow_table(arrow_table, description), num_rows
689
687
 
@@ -692,7 +690,7 @@ class ThriftDatabricksClient(DatabricksClient):
692
690
  return self.make_request(self._client.GetResultSetMetadata, req)
693
691
 
694
692
  @staticmethod
695
- def _hive_schema_to_arrow_schema(t_table_schema, session_id_hex=None):
693
+ def _hive_schema_to_arrow_schema(t_table_schema, host_url=None):
696
694
  def map_type(t_type_entry):
697
695
  if t_type_entry.primitiveEntry:
698
696
  return {
@@ -724,7 +722,7 @@ class ThriftDatabricksClient(DatabricksClient):
724
722
  # even for complex types
725
723
  raise OperationalError(
726
724
  "Thrift protocol error: t_type_entry not a primitiveEntry",
727
- session_id_hex=session_id_hex,
725
+ host_url=host_url,
728
726
  )
729
727
 
730
728
  def convert_col(t_column_desc):
@@ -735,7 +733,7 @@ class ThriftDatabricksClient(DatabricksClient):
735
733
  return pyarrow.schema([convert_col(col) for col in t_table_schema.columns])
736
734
 
737
735
  @staticmethod
738
- def _col_to_description(col, field=None, session_id_hex=None):
736
+ def _col_to_description(col, field=None, host_url=None):
739
737
  type_entry = col.typeDesc.types[0]
740
738
 
741
739
  if type_entry.primitiveEntry:
@@ -745,7 +743,7 @@ class ThriftDatabricksClient(DatabricksClient):
745
743
  else:
746
744
  raise OperationalError(
747
745
  "Thrift protocol error: t_type_entry not a primitiveEntry",
748
- session_id_hex=session_id_hex,
746
+ host_url=host_url,
749
747
  )
750
748
 
751
749
  if type_entry.primitiveEntry.type == ttypes.TTypeId.DECIMAL_TYPE:
@@ -759,7 +757,7 @@ class ThriftDatabricksClient(DatabricksClient):
759
757
  raise OperationalError(
760
758
  "Decimal type did not provide typeQualifier precision, scale in "
761
759
  "primitiveEntry {}".format(type_entry.primitiveEntry),
762
- session_id_hex=session_id_hex,
760
+ host_url=host_url,
763
761
  )
764
762
  else:
765
763
  precision, scale = None, None
@@ -778,9 +776,7 @@ class ThriftDatabricksClient(DatabricksClient):
778
776
  return col.columnName, cleaned_type, None, None, precision, scale, None
779
777
 
780
778
  @staticmethod
781
- def _hive_schema_to_description(
782
- t_table_schema, schema_bytes=None, session_id_hex=None
783
- ):
779
+ def _hive_schema_to_description(t_table_schema, schema_bytes=None, host_url=None):
784
780
  field_dict = {}
785
781
  if pyarrow and schema_bytes:
786
782
  try:
@@ -795,7 +791,7 @@ class ThriftDatabricksClient(DatabricksClient):
795
791
  ThriftDatabricksClient._col_to_description(
796
792
  col,
797
793
  field_dict.get(col.columnName) if field_dict else None,
798
- session_id_hex,
794
+ host_url,
799
795
  )
800
796
  for col in t_table_schema.columns
801
797
  ]
@@ -818,7 +814,7 @@ class ThriftDatabricksClient(DatabricksClient):
818
814
  t_result_set_metadata_resp.resultFormat
819
815
  ]
820
816
  ),
821
- session_id_hex=self._session_id_hex,
817
+ host_url=self._host,
822
818
  )
823
819
  direct_results = resp.directResults
824
820
  has_been_closed_server_side = direct_results and direct_results.closeOperation
@@ -833,7 +829,7 @@ class ThriftDatabricksClient(DatabricksClient):
833
829
  schema_bytes = (
834
830
  t_result_set_metadata_resp.arrowSchema
835
831
  or self._hive_schema_to_arrow_schema(
836
- t_result_set_metadata_resp.schema, self._session_id_hex
832
+ t_result_set_metadata_resp.schema, self._host
837
833
  )
838
834
  .serialize()
839
835
  .to_pybytes()
@@ -844,7 +840,7 @@ class ThriftDatabricksClient(DatabricksClient):
844
840
  description = self._hive_schema_to_description(
845
841
  t_result_set_metadata_resp.schema,
846
842
  schema_bytes,
847
- self._session_id_hex,
843
+ self._host,
848
844
  )
849
845
 
850
846
  lz4_compressed = t_result_set_metadata_resp.lz4Compressed
@@ -895,7 +891,7 @@ class ThriftDatabricksClient(DatabricksClient):
895
891
  schema_bytes = (
896
892
  t_result_set_metadata_resp.arrowSchema
897
893
  or self._hive_schema_to_arrow_schema(
898
- t_result_set_metadata_resp.schema, self._session_id_hex
894
+ t_result_set_metadata_resp.schema, self._host
899
895
  )
900
896
  .serialize()
901
897
  .to_pybytes()
@@ -906,7 +902,7 @@ class ThriftDatabricksClient(DatabricksClient):
906
902
  description = self._hive_schema_to_description(
907
903
  t_result_set_metadata_resp.schema,
908
904
  schema_bytes,
909
- self._session_id_hex,
905
+ self._host,
910
906
  )
911
907
 
912
908
  lz4_compressed = t_result_set_metadata_resp.lz4Compressed
@@ -971,27 +967,27 @@ class ThriftDatabricksClient(DatabricksClient):
971
967
  return state
972
968
 
973
969
  @staticmethod
974
- def _check_direct_results_for_error(t_spark_direct_results, session_id_hex=None):
970
+ def _check_direct_results_for_error(t_spark_direct_results, host_url=None):
975
971
  if t_spark_direct_results:
976
972
  if t_spark_direct_results.operationStatus:
977
973
  ThriftDatabricksClient._check_response_for_error(
978
974
  t_spark_direct_results.operationStatus,
979
- session_id_hex,
975
+ host_url,
980
976
  )
981
977
  if t_spark_direct_results.resultSetMetadata:
982
978
  ThriftDatabricksClient._check_response_for_error(
983
979
  t_spark_direct_results.resultSetMetadata,
984
- session_id_hex,
980
+ host_url,
985
981
  )
986
982
  if t_spark_direct_results.resultSet:
987
983
  ThriftDatabricksClient._check_response_for_error(
988
984
  t_spark_direct_results.resultSet,
989
- session_id_hex,
985
+ host_url,
990
986
  )
991
987
  if t_spark_direct_results.closeOperation:
992
988
  ThriftDatabricksClient._check_response_for_error(
993
989
  t_spark_direct_results.closeOperation,
994
- session_id_hex,
990
+ host_url,
995
991
  )
996
992
 
997
993
  def execute_command(
@@ -1260,7 +1256,7 @@ class ThriftDatabricksClient(DatabricksClient):
1260
1256
  raise ValueError(f"Invalid Thrift handle: {resp.operationHandle}")
1261
1257
 
1262
1258
  cursor.active_command_id = command_id
1263
- self._check_direct_results_for_error(resp.directResults, self._session_id_hex)
1259
+ self._check_direct_results_for_error(resp.directResults, self._host)
1264
1260
 
1265
1261
  final_operation_state = self._wait_until_command_done(
1266
1262
  resp.operationHandle,
@@ -1275,7 +1271,7 @@ class ThriftDatabricksClient(DatabricksClient):
1275
1271
  raise ValueError(f"Invalid Thrift handle: {resp.operationHandle}")
1276
1272
 
1277
1273
  cursor.active_command_id = command_id
1278
- self._check_direct_results_for_error(resp.directResults, self._session_id_hex)
1274
+ self._check_direct_results_for_error(resp.directResults, self._host)
1279
1275
 
1280
1276
  def fetch_results(
1281
1277
  self,
@@ -1313,7 +1309,7 @@ class ThriftDatabricksClient(DatabricksClient):
1313
1309
  "fetch_results failed due to inconsistency in the state between the client and the server. Expected results to start from {} but they instead start at {}, some result batches must have been skipped".format(
1314
1310
  expected_row_start_offset, resp.results.startRowOffset
1315
1311
  ),
1316
- session_id_hex=self._session_id_hex,
1312
+ host_url=self._host,
1317
1313
  )
1318
1314
 
1319
1315
  queue = ThriftResultSetQueueFactory.build_queue(
@@ -328,7 +328,7 @@ class Connection:
328
328
  self.ignore_transactions = ignore_transactions
329
329
 
330
330
  self.force_enable_telemetry = kwargs.get("force_enable_telemetry", False)
331
- self.enable_telemetry = kwargs.get("enable_telemetry", False)
331
+ self.enable_telemetry = kwargs.get("enable_telemetry", True)
332
332
  self.telemetry_enabled = TelemetryHelper.is_telemetry_enabled(self)
333
333
 
334
334
  TelemetryClientFactory.initialize_telemetry_client(
@@ -341,7 +341,7 @@ class Connection:
341
341
  )
342
342
 
343
343
  self._telemetry_client = TelemetryClientFactory.get_telemetry_client(
344
- session_id_hex=self.get_session_id_hex()
344
+ host_url=self.session.host
345
345
  )
346
346
 
347
347
  # Determine proxy usage
@@ -391,6 +391,7 @@ class Connection:
391
391
  self._telemetry_client.export_initial_telemetry_log(
392
392
  driver_connection_params=driver_connection_params,
393
393
  user_agent=self.session.useragent_header,
394
+ session_id=self.get_session_id_hex(),
394
395
  )
395
396
 
396
397
  def _set_use_inline_params_with_warning(self, value: Union[bool, str]):
@@ -494,6 +495,7 @@ class Connection:
494
495
  if not self.open:
495
496
  raise InterfaceError(
496
497
  "Cannot create cursor from closed connection",
498
+ host_url=self.session.host,
497
499
  session_id_hex=self.get_session_id_hex(),
498
500
  )
499
501
 
@@ -521,7 +523,7 @@ class Connection:
521
523
  except Exception as e:
522
524
  logger.error(f"Attempt to close session raised a local exception: {e}")
523
525
 
524
- TelemetryClientFactory.close(self.get_session_id_hex())
526
+ TelemetryClientFactory.close(host_url=self.session.host)
525
527
 
526
528
  # Close HTTP client that was created by this connection
527
529
  if self.http_client:
@@ -546,6 +548,7 @@ class Connection:
546
548
  if not self.open:
547
549
  raise InterfaceError(
548
550
  "Cannot get autocommit on closed connection",
551
+ host_url=self.session.host,
549
552
  session_id_hex=self.get_session_id_hex(),
550
553
  )
551
554
 
@@ -578,6 +581,7 @@ class Connection:
578
581
  if not self.open:
579
582
  raise InterfaceError(
580
583
  "Cannot set autocommit on closed connection",
584
+ host_url=self.session.host,
581
585
  session_id_hex=self.get_session_id_hex(),
582
586
  )
583
587
 
@@ -600,6 +604,7 @@ class Connection:
600
604
  "operation": "set_autocommit",
601
605
  "autocommit_value": value,
602
606
  },
607
+ host_url=self.session.host,
603
608
  session_id_hex=self.get_session_id_hex(),
604
609
  ) from e
605
610
  finally:
@@ -627,6 +632,7 @@ class Connection:
627
632
  raise TransactionError(
628
633
  "No result returned from SET AUTOCOMMIT query",
629
634
  context={"operation": "fetch_autocommit"},
635
+ host_url=self.session.host,
630
636
  session_id_hex=self.get_session_id_hex(),
631
637
  )
632
638
 
@@ -647,6 +653,7 @@ class Connection:
647
653
  raise TransactionError(
648
654
  f"Failed to fetch autocommit state from server: {e.message}",
649
655
  context={**e.context, "operation": "fetch_autocommit"},
656
+ host_url=self.session.host,
650
657
  session_id_hex=self.get_session_id_hex(),
651
658
  ) from e
652
659
  finally:
@@ -680,6 +687,7 @@ class Connection:
680
687
  if not self.open:
681
688
  raise InterfaceError(
682
689
  "Cannot commit on closed connection",
690
+ host_url=self.session.host,
683
691
  session_id_hex=self.get_session_id_hex(),
684
692
  )
685
693
 
@@ -692,6 +700,7 @@ class Connection:
692
700
  raise TransactionError(
693
701
  f"Failed to commit transaction: {e.message}",
694
702
  context={**e.context, "operation": "commit"},
703
+ host_url=self.session.host,
695
704
  session_id_hex=self.get_session_id_hex(),
696
705
  ) from e
697
706
  finally:
@@ -725,12 +734,14 @@ class Connection:
725
734
  if self.ignore_transactions:
726
735
  raise NotSupportedError(
727
736
  "Transactions are not supported on Databricks",
737
+ host_url=self.session.host,
728
738
  session_id_hex=self.get_session_id_hex(),
729
739
  )
730
740
 
731
741
  if not self.open:
732
742
  raise InterfaceError(
733
743
  "Cannot rollback on closed connection",
744
+ host_url=self.session.host,
734
745
  session_id_hex=self.get_session_id_hex(),
735
746
  )
736
747
 
@@ -743,6 +754,7 @@ class Connection:
743
754
  raise TransactionError(
744
755
  f"Failed to rollback transaction: {e.message}",
745
756
  context={**e.context, "operation": "rollback"},
757
+ host_url=self.session.host,
746
758
  session_id_hex=self.get_session_id_hex(),
747
759
  ) from e
748
760
  finally:
@@ -767,6 +779,7 @@ class Connection:
767
779
  if not self.open:
768
780
  raise InterfaceError(
769
781
  "Cannot get transaction isolation on closed connection",
782
+ host_url=self.session.host,
770
783
  session_id_hex=self.get_session_id_hex(),
771
784
  )
772
785
 
@@ -793,6 +806,7 @@ class Connection:
793
806
  if not self.open:
794
807
  raise InterfaceError(
795
808
  "Cannot set transaction isolation on closed connection",
809
+ host_url=self.session.host,
796
810
  session_id_hex=self.get_session_id_hex(),
797
811
  )
798
812
 
@@ -805,6 +819,7 @@ class Connection:
805
819
  raise NotSupportedError(
806
820
  f"Setting transaction isolation level '{level}' is not supported. "
807
821
  f"Only {TRANSACTION_ISOLATION_LEVEL_REPEATABLE_READ} is supported.",
822
+ host_url=self.session.host,
808
823
  session_id_hex=self.get_session_id_hex(),
809
824
  )
810
825
 
@@ -857,6 +872,7 @@ class Cursor:
857
872
  else:
858
873
  raise ProgrammingError(
859
874
  "There is no active result set",
875
+ host_url=self.connection.session.host,
860
876
  session_id_hex=self.connection.get_session_id_hex(),
861
877
  )
862
878
 
@@ -997,6 +1013,7 @@ class Cursor:
997
1013
  if not self.open:
998
1014
  raise InterfaceError(
999
1015
  "Attempting operation on closed cursor",
1016
+ host_url=self.connection.session.host,
1000
1017
  session_id_hex=self.connection.get_session_id_hex(),
1001
1018
  )
1002
1019
 
@@ -1041,6 +1058,7 @@ class Cursor:
1041
1058
  else:
1042
1059
  raise ProgrammingError(
1043
1060
  "You must provide at least one staging_allowed_local_path when initialising a connection to perform ingestion commands",
1061
+ host_url=self.connection.session.host,
1044
1062
  session_id_hex=self.connection.get_session_id_hex(),
1045
1063
  )
1046
1064
 
@@ -1067,6 +1085,7 @@ class Cursor:
1067
1085
  if not allow_operation:
1068
1086
  raise ProgrammingError(
1069
1087
  "Local file operations are restricted to paths within the configured staging_allowed_local_path",
1088
+ host_url=self.connection.session.host,
1070
1089
  session_id_hex=self.connection.get_session_id_hex(),
1071
1090
  )
1072
1091
 
@@ -1095,6 +1114,7 @@ class Cursor:
1095
1114
  raise ProgrammingError(
1096
1115
  f"Operation {row.operation} is not supported. "
1097
1116
  + "Supported operations are GET, PUT, and REMOVE",
1117
+ host_url=self.connection.session.host,
1098
1118
  session_id_hex=self.connection.get_session_id_hex(),
1099
1119
  )
1100
1120
 
@@ -1110,6 +1130,7 @@ class Cursor:
1110
1130
  if local_file is None:
1111
1131
  raise ProgrammingError(
1112
1132
  "Cannot perform PUT without specifying a local_file",
1133
+ host_url=self.connection.session.host,
1113
1134
  session_id_hex=self.connection.get_session_id_hex(),
1114
1135
  )
1115
1136
 
@@ -1135,6 +1156,7 @@ class Cursor:
1135
1156
  error_text = r.data.decode() if r.data else ""
1136
1157
  raise OperationalError(
1137
1158
  f"Staging operation over HTTP was unsuccessful: {r.status}-{error_text}",
1159
+ host_url=self.connection.session.host,
1138
1160
  session_id_hex=self.connection.get_session_id_hex(),
1139
1161
  )
1140
1162
 
@@ -1166,6 +1188,7 @@ class Cursor:
1166
1188
  if not stream:
1167
1189
  raise ProgrammingError(
1168
1190
  "No input stream provided for streaming operation",
1191
+ host_url=self.connection.session.host,
1169
1192
  session_id_hex=self.connection.get_session_id_hex(),
1170
1193
  )
1171
1194
 
@@ -1187,6 +1210,7 @@ class Cursor:
1187
1210
  if local_file is None:
1188
1211
  raise ProgrammingError(
1189
1212
  "Cannot perform GET without specifying a local_file",
1213
+ host_url=self.connection.session.host,
1190
1214
  session_id_hex=self.connection.get_session_id_hex(),
1191
1215
  )
1192
1216
 
@@ -1201,6 +1225,7 @@ class Cursor:
1201
1225
  error_text = r.data.decode() if r.data else ""
1202
1226
  raise OperationalError(
1203
1227
  f"Staging operation over HTTP was unsuccessful: {r.status}-{error_text}",
1228
+ host_url=self.connection.session.host,
1204
1229
  session_id_hex=self.connection.get_session_id_hex(),
1205
1230
  )
1206
1231
 
@@ -1222,6 +1247,7 @@ class Cursor:
1222
1247
  error_text = r.data.decode() if r.data else ""
1223
1248
  raise OperationalError(
1224
1249
  f"Staging operation over HTTP was unsuccessful: {r.status}-{error_text}",
1250
+ host_url=self.connection.session.host,
1225
1251
  session_id_hex=self.connection.get_session_id_hex(),
1226
1252
  )
1227
1253
 
@@ -1413,6 +1439,7 @@ class Cursor:
1413
1439
  else:
1414
1440
  raise OperationalError(
1415
1441
  f"get_execution_result failed with Operation status {operation_state}",
1442
+ host_url=self.connection.session.host,
1416
1443
  session_id_hex=self.connection.get_session_id_hex(),
1417
1444
  )
1418
1445
 
@@ -1541,6 +1568,7 @@ class Cursor:
1541
1568
  else:
1542
1569
  raise ProgrammingError(
1543
1570
  "There is no active result set",
1571
+ host_url=self.connection.session.host,
1544
1572
  session_id_hex=self.connection.get_session_id_hex(),
1545
1573
  )
1546
1574
 
@@ -1558,6 +1586,7 @@ class Cursor:
1558
1586
  else:
1559
1587
  raise ProgrammingError(
1560
1588
  "There is no active result set",
1589
+ host_url=self.connection.session.host,
1561
1590
  session_id_hex=self.connection.get_session_id_hex(),
1562
1591
  )
1563
1592
 
@@ -1583,6 +1612,7 @@ class Cursor:
1583
1612
  else:
1584
1613
  raise ProgrammingError(
1585
1614
  "There is no active result set",
1615
+ host_url=self.connection.session.host,
1586
1616
  session_id_hex=self.connection.get_session_id_hex(),
1587
1617
  )
1588
1618
 
@@ -1593,6 +1623,7 @@ class Cursor:
1593
1623
  else:
1594
1624
  raise ProgrammingError(
1595
1625
  "There is no active result set",
1626
+ host_url=self.connection.session.host,
1596
1627
  session_id_hex=self.connection.get_session_id_hex(),
1597
1628
  )
1598
1629
 
@@ -1603,6 +1634,7 @@ class Cursor:
1603
1634
  else:
1604
1635
  raise ProgrammingError(
1605
1636
  "There is no active result set",
1637
+ host_url=self.connection.session.host,
1606
1638
  session_id_hex=self.connection.get_session_id_hex(),
1607
1639
  )
1608
1640