Skip to content

Commit 3305d43

Browse files
fix(volume): preserve local validation errors and document release gate
Signed-off-by: Aakash Saravanan <aakash.saravanan@databricks.com>
1 parent c09ff98 commit 3305d43

6 files changed

Lines changed: 21 additions & 5 deletions

File tree

‎KERNEL_REV‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
ebb8204b36951b751dd837b2c41ced8c821b2d94
1+
02283500d50e1bcd61007e0cf04a7e1e3d16ea86

‎pyproject.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ requests-kerberos = {version = "^0.15.0", optional = true}
7070
# Floor is 1.4.0 (``^1.4.0`` == ``>=1.4.0,<2.0.0``), allowing compatible
7171
# 1.x releases while keeping the next major upgrade deliberate. The kernel's
7272
# pyarrow constraint remains >=23.0.1,<24.
73+
# TODO: raise the release floor after databricks/databricks-sql-kernel#439 is published.
7374
databricks-sql-kernel = {version = "^1.4.0", optional = true, python = ">=3.10"}
7475

7576

‎src/databricks/sql/backend/kernel/_errors.py‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
"only PEP 249 exception types cross the boundary". Wrapped in
1818
``OperationalError`` here.
1919
20+
Local missing transfer files deliberately retain the built-in
21+
``FileNotFoundError`` contract.
22+
2023
These primitives live in their own module so both ``client.py``
2124
(which orchestrates PyO3 calls) and ``result_set.py`` (which calls
2225
``fetch_next_batch`` on the same kernel handles) can share them
@@ -133,7 +136,8 @@ def reraise_kernel_error(
133136
if file_transfer:
134137
cls = (
135138
ProgrammingError
136-
if code == "PermissionDenied" and getattr(exc, "http_status", None) is None
139+
if code in ("PermissionDenied", "InvalidArgument")
140+
and getattr(exc, "http_status", None) is None
137141
else OperationalError
138142
)
139143

@@ -185,9 +189,10 @@ def reraise_kernel_error(
185189
def wrap_kernel_exception(
186190
what: str, exc: BaseException
187191
) -> "Union[Error, FileNotFoundError]":
188-
"""Map any exception from a PyO3 call site to a PEP 249 exception.
192+
"""Map a PyO3 exception to the connector's public error contract.
189193
190194
- ``KernelError`` → mapped class with structured attrs forwarded.
195+
A local missing transfer file maps to ``FileNotFoundError``.
191196
- Already-PEP-249 ``Error`` (e.g. raised by an inner caller that
192197
already mapped) → passed through unchanged.
193198
- Anything else (``TypeError`` / ``ValueError`` / etc. from PyO3

‎src/databricks/sql/client.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1394,7 +1394,7 @@ def _handle_staging_put(
13941394
session_id_hex=self.connection.get_session_id_hex(),
13951395
)
13961396

1397-
# Kernel backends reject staging operations before reaching these handlers.
1397+
# The kernel completes configured transfers before reaching these handlers.
13981398
assert self.connection.http_client is not None
13991399
with open(local_file, "rb") as fh:
14001400
r = self.connection.http_client.request(

‎tests/e2e/test_kernel_backend.py‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,9 @@ def test_schemas_with_empty_string_filter_matches_nothing(conn):
367367
assert cur.fetchall() == []
368368

369369

370-
@pytest.mark.parametrize("empty_filter", ["schema_name", "table_name", "column_name"])
370+
@pytest.mark.parametrize(
371+
"empty_filter", ["schema_name", "table_name", "column_name"]
372+
)
371373
def test_columns_with_empty_string_filter_matches_nothing(conn, empty_filter):
372374
filters = {
373375
"catalog_name": "system",
@@ -798,6 +800,13 @@ def test_volume_file_lifecycle(kernel_conn_params, tmp_path, catalog, async_op):
798800
try:
799801
cur.execute(f"CREATE VOLUME {qualified}.files")
800802

803+
with sql.connect(**kernel_conn_params) as no_paths:
804+
with no_paths.cursor() as denied_cursor:
805+
with pytest.raises(ProgrammingError):
806+
denied_cursor.execute(
807+
f"PUT '{source}' INTO '{remote}' OVERWRITE"
808+
)
809+
801810
def execute(query):
802811
if async_op:
803812
cur.execute_async(query)

‎tests/unit/test_kernel_client.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2621,6 +2621,7 @@ def test_only_reserved_headers_omits_kwarg(self, monkeypatch):
26212621
"code, http_status, expected",
26222622
[
26232623
("PermissionDenied", None, ProgrammingError),
2624+
("InvalidArgument", None, ProgrammingError),
26242625
("PermissionDenied", 403, OperationalError),
26252626
("NotFound", None, FileNotFoundError),
26262627
("NotFound", 404, OperationalError),

0 commit comments

Comments
 (0)