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
2 changes: 1 addition & 1 deletion .codegen/_last_sha
Original file line number Diff line number Diff line change
@@ -1 +1 @@
c765e364f87ce050e4077db80b8ec800c9ec1ed9
231772f37bb5c01154bfc3d1401dc241ff1b7409
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Version changelog

## Release v0.143.0 (2026-09-26)

### API Changes
* Add `job_id` and `pipeline_id` fields for `databricks.sdk.service.ml.MaterializedFeature`.

### Bug Fixes
* Don't configure the root logger when importing `databricks.sdk.runtime`. Its import-time notebook-globals initialization logged through root-level `logging` helpers, which install a handler on the root logger when it has none. This also happened transitively through `WorkspaceClient` and `dbutils`, and made a later `logging.basicConfig()` a silent no-op. These messages now go through the SDK's `databricks.sdk` logger.

## Release v0.142.0 (2026-09-25)

### API Changes
Expand Down
8 changes: 4 additions & 4 deletions databricks/sdk/runtime/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,12 @@ def inner() -> Dict[str, str]:
sqlContext: SQLContext = None # type: ignore
table = sqlContext.table
except Exception as e:
logging.debug(f"Failed to initialize globals 'sqlContext' and 'table', continuing. Cause: {e}")
logger.debug(f"Failed to initialize globals 'sqlContext' and 'table', continuing. Cause: {e}")

try:
from pyspark.sql.functions import udf # type: ignore # noqa: F401
except ImportError as e:
logging.debug(f"Failed to initialise udf global: {e}")
logger.debug(f"Failed to initialise udf global: {e}")

try:
from databricks.connect import DatabricksSession # type: ignore
Expand All @@ -153,13 +153,13 @@ def inner() -> Dict[str, str]:
except Exception as e:
# We are ignoring all failures here because user might want to initialize
# spark session themselves and we don't want to interfere with that
logging.debug(f"Failed to initialize globals 'spark' and 'sql', continuing. Cause: {e}")
logger.debug(f"Failed to initialize globals 'spark' and 'sql', continuing. Cause: {e}")

try:
# We expect this to fail locally since dbconnect does not support sparkcontext. This is just for typing
sc = spark.sparkContext # type: ignore
except Exception as e:
logging.debug(f"Failed to initialize global 'sc', continuing. Cause: {e}")
logger.debug(f"Failed to initialize global 'sc', continuing. Cause: {e}")

def display(input=None, *args, **kwargs) -> None: # type: ignore
"""
Expand Down
18 changes: 18 additions & 0 deletions databricks/sdk/service/ml.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion databricks/sdk/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.142.0"
__version__ = "0.143.0"
38 changes: 38 additions & 0 deletions tests/test_runtime.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""Tests for the import-time behavior of ``databricks.sdk.runtime``."""

import subprocess
import sys
import textwrap
import types

import pytest
Expand Down Expand Up @@ -60,3 +62,39 @@ def test_workspace_client_constructs_on_spark_connect(spark_connect_runtime, con
ws = WorkspaceClient(config=config)

assert ws is not None


def test_import_does_not_configure_root_logger():
"""Importing the module must not install a handler on the root logger.

The module logs from its import-time global-init blocks. Routing those through the
root ``logging.<level>()`` functions calls ``logging.basicConfig()`` while the root
logger has no handler, which installs one -- so a downstream ``logging.basicConfig()``
silently becomes a no-op and the importer's logs vanish. Run in a subprocess with a
clean root logger, since this process has already imported the module (and configured
logging), and the module is import-cached.
"""
check = textwrap.dedent(
"""
import logging
import sys

# databricks-connect is installed here; force its import in the OSS fallback to fail
# fast so the block logs via the ImportError path instead of trying to open a session.
sys.modules["databricks.connect"] = None

assert not logging.getLogger().handlers, "precondition: root logger starts clean"
try:
import databricks.sdk.runtime # noqa: F401
except Exception:
# The fallback ends by building RemoteDbUtils()/Config, which can fail or block on
# host resolution without credentials. That runs *after* the import-time global-init
# logging this test guards, so tolerate it -- we only assert the root logger was
# left untouched by that earlier logging.
pass
handlers = logging.getLogger().handlers
assert not handlers, f"import configured the root logger: {handlers!r}"
"""
)
result = subprocess.run([sys.executable, "-c", check], capture_output=True, text=True)
assert result.returncode == 0, f"stdout:\n{result.stdout}\nstderr:\n{result.stderr}"
Loading