Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions .github/workflows/code-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,32 @@ jobs:
- name: Install library
run: poetry install --no-interaction --all-extras
#----------------------------------------------
# run all tests with coverage
# run parallel tests with coverage
#----------------------------------------------
- name: Run all tests with coverage
- name: Run parallel tests with coverage
continue-on-error: false
run: |
poetry run pytest tests/unit tests/e2e \
-m "not serial" \
-n auto \
--cov=src \
--cov-report=xml \
--cov-report=term \
-v

#----------------------------------------------
# run serial tests with coverage
#----------------------------------------------
- name: Run serial tests with coverage
continue-on-error: false
run: |
poetry run pytest tests/e2e \
-m "serial" \
--cov=src \
--cov-append \
--cov-report=xml \
--cov-report=term \
-v

#----------------------------------------------
# check for coverage override
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Release History

# 4.2.2 (2025-12-01)
- Change default use_hybrid_disposition to False (databricks/databricks-sql-python#714 by @samikshya-db)
- Circuit breaker changes using pybreaker (databricks/databricks-sql-python#705 by @nikhilsuri-db)
- perf: Optimize telemetry latency logging to reduce overhead (databricks/databricks-sql-python#715 by @samikshya-db)
- basic e2e test for force telemetry verification (databricks/databricks-sql-python#708 by @nikhilsuri-db)
- 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)

# 4.2.1 (2025-11-20)
- Ignore transactions by default (databricks/databricks-sql-python#711 by @jayantsing-db)

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ You are welcome to file an issue here for general use cases. You can also contac

## Requirements

Python 3.8 or above is required.
Python 3.9 or above is required.

## Documentation

Expand Down
7 changes: 5 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "databricks-sql-connector"
version = "4.2.1"
version = "4.2.2"
description = "Databricks SQL Connector for Python"
authors = ["Databricks <[email protected]>"]
license = "Apache-2.0"
Expand Down Expand Up @@ -62,7 +62,10 @@ exclude = ['ttypes\.py$', 'TCLIService\.py$']
exclude = '/(\.eggs|\.git|\.hg|\.mypy_cache|\.nox|\.tox|\.venv|\.svn|_build|buck-out|build|dist|thrift_api)/'

[tool.pytest.ini_options]
markers = {"reviewed" = "Test case has been reviewed by Databricks"}
markers = [
"reviewed: Test case has been reviewed by Databricks",
"serial: Tests that must run serially (not parallelized)"
]
minversion = "6.0"
log_cli = "false"
log_cli_level = "INFO"
Expand Down
2 changes: 1 addition & 1 deletion src/databricks/sql/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def __repr__(self):
DATE = DBAPITypeObject("date")
ROWID = DBAPITypeObject()

__version__ = "4.2.1"
__version__ = "4.2.2"
USER_AGENT_NAME = "PyDatabricksSqlConnector"

# These two functions are pyhive legacy
Expand Down
2 changes: 1 addition & 1 deletion src/databricks/sql/auth/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(
pool_connections: Optional[int] = None,
pool_maxsize: Optional[int] = None,
user_agent: Optional[str] = None,
telemetry_circuit_breaker_enabled: Optional[bool] = None,
telemetry_circuit_breaker_enabled: Optional[bool] = True,
):
self.hostname = hostname
self.access_token = access_token
Expand Down
2 changes: 1 addition & 1 deletion src/databricks/sql/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ def read(self) -> Optional[OAuthToken]:
self.ignore_transactions = ignore_transactions

self.force_enable_telemetry = kwargs.get("force_enable_telemetry", False)
self.enable_telemetry = kwargs.get("enable_telemetry", False)
self.enable_telemetry = kwargs.get("enable_telemetry", True)
self.telemetry_enabled = TelemetryHelper.is_telemetry_enabled(self)

TelemetryClientFactory.initialize_telemetry_client(
Expand Down
1 change: 1 addition & 0 deletions tests/e2e/test_concurrent_telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def run_in_threads(target, num_threads, pass_index=False):
t.join()


@pytest.mark.serial
class TestE2ETelemetry(PySQLPytestTestCase):
@pytest.fixture(autouse=True)
def telemetry_setup_teardown(self):
Expand Down
17 changes: 14 additions & 3 deletions tests/e2e/test_telemetry_e2e.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ def connection(self, extra_params=()):
conn.close()


@pytest.mark.serial
class TestTelemetryE2E(TelemetryTestBase):
"""E2E tests for telemetry scenarios"""
"""E2E tests for telemetry scenarios - must run serially due to shared host-level telemetry client"""

@pytest.fixture(autouse=True)
def telemetry_setup_teardown(self):
Expand All @@ -58,6 +59,14 @@ def telemetry_setup_teardown(self):
TelemetryClientFactory._stop_flush_thread()
TelemetryClientFactory._initialized = False

# Clear feature flags cache to prevent state leakage between tests
from databricks.sql.common.feature_flag import FeatureFlagsContextFactory
with FeatureFlagsContextFactory._lock:
FeatureFlagsContextFactory._context_map.clear()
if FeatureFlagsContextFactory._executor:
FeatureFlagsContextFactory._executor.shutdown(wait=False)
FeatureFlagsContextFactory._executor = None

@pytest.fixture
def telemetry_interceptors(self):
"""Setup reusable telemetry interceptors as a fixture"""
Expand Down Expand Up @@ -142,7 +151,7 @@ def verify_events(self, captured_events, captured_futures, expected_count):
else:
assert len(captured_events) == expected_count, \
f"Expected {expected_count} events, got {len(captured_events)}"

time.sleep(2)
done, _ = wait(captured_futures, timeout=10)
assert len(done) == expected_count, \
Expand All @@ -163,7 +172,7 @@ def verify_events(self, captured_events, captured_futures, expected_count):
(True, False, 2, "enable_on_force_off"),
(False, True, 2, "enable_off_force_on"),
(False, False, 0, "both_off"),
(None, None, 0, "default_behavior"),
(None, None, 2, "default_behavior"),
])
def test_telemetry_flags(self, telemetry_interceptors, enable_telemetry,
force_enable, expected_count, test_id):
Expand All @@ -185,6 +194,8 @@ def test_telemetry_flags(self, telemetry_interceptors, enable_telemetry,
cursor.execute("SELECT 1")
cursor.fetchone()

# Give time for async telemetry submission after connection closes
time.sleep(0.5)
self.verify_events(captured_events, captured_futures, expected_count)

# Assert statement execution on latency event (if events exist)
Expand Down
Loading