Skip to content

Commit b254618

Browse files
committed
tidy: format
1 parent 242de3c commit b254618

File tree

3 files changed

+73
-35
lines changed

3 files changed

+73
-35
lines changed

marimo/_sql/error_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def is_sql_parse_error(exception: BaseException) -> bool:
6565
duckdb.IOException,
6666
duckdb.OperationalError,
6767
duckdb.IntegrityError,
68-
duckdb.DataError
68+
duckdb.DataError,
6969
),
7070
):
7171
return True
@@ -213,7 +213,6 @@ def log_sql_error(
213213
logger_func(log_msg, extra=metadata)
214214

215215

216-
217216
def create_sql_error_from_exception(
218217
exception: BaseException,
219218
cell: object,
@@ -228,6 +227,7 @@ def create_sql_error_from_exception(
228227
if isinstance(exception, MarimoSQLException) and exception.hint:
229228
# Use the structured hint data from the exception
230229
from marimo._messaging.errors import MarimoSQLError
230+
231231
return MarimoSQLError(
232232
msg=str(exception),
233233
sql_statement=exception.sql_statement,

marimo/_sql/sql.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,9 @@ def sql(
104104
clean_message = f"SQL programming error: {clean_message}"
105105

106106
# Truncate long SQL statements
107-
truncated_query = query[:200] + "..." if len(query) > 200 else query
107+
truncated_query = (
108+
query[:200] + "..." if len(query) > 200 else query
109+
)
108110

109111
# Raise MarimoSQLException with structured hint data
110112
raise MarimoSQLException(

tests/_sql/test_sql_error_handling.py

Lines changed: 68 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
from __future__ import annotations
44

5-
from unittest.mock import patch
6-
75
import pytest
86

97
from marimo._dependencies.dependencies import DependencyManager
@@ -64,7 +62,10 @@ def test_syntax_error_malformed_expression(self):
6462
sql("SELECT ( FROM table")
6563

6664
error = exc_info.value
67-
assert "syntax error" in str(error).lower() or "parser error" in str(error).lower()
65+
assert (
66+
"syntax error" in str(error).lower()
67+
or "parser error" in str(error).lower()
68+
)
6869

6970
@pytest.mark.skipif(not HAS_DUCKDB, reason="DuckDB not installed")
7071
def test_data_type_error(self):
@@ -82,7 +83,11 @@ def test_data_type_error(self):
8283
@pytest.mark.skipif(not HAS_DUCKDB, reason="DuckDB not installed")
8384
def test_long_sql_statement_truncation(self):
8485
"""Test that long SQL statements are truncated in error messages."""
85-
long_query = "SELECT " + ", ".join([f"col_{i}" for i in range(100)]) + " FROM nonexistent_table"
86+
long_query = (
87+
"SELECT "
88+
+ ", ".join([f"col_{i}" for i in range(100)])
89+
+ " FROM nonexistent_table"
90+
)
8691

8792
with pytest.raises(MarimoSQLException) as exc_info:
8893
sql(long_query)
@@ -152,26 +157,23 @@ def test_is_sql_parse_error_duckdb(self):
152157
"""Test detection of DuckDB parsing errors."""
153158
import duckdb
154159

155-
try:
160+
with pytest.raises(Exception) as exc_info:
156161
duckdb.sql("SELECT * FROM nonexistent_table")
157-
except Exception as e:
158-
assert is_sql_parse_error(e) is True
162+
assert is_sql_parse_error(exc_info.value) is True
159163

160-
try:
164+
with pytest.raises(Exception) as exc_info:
161165
duckdb.sql("SELECT * FRM invalid_syntax")
162-
except Exception as e:
163-
assert is_sql_parse_error(e) is True
166+
assert is_sql_parse_error(exc_info.value) is True
164167

165168
@pytest.mark.skipif(not HAS_SQLGLOT, reason="SQLGlot not installed")
166169
def test_is_sql_parse_error_sqlglot(self):
167170
"""Test detection of SQLGlot parsing errors."""
168171
from sqlglot import parse_one
169172
from sqlglot.errors import ParseError
170173

171-
try:
174+
with pytest.raises(ParseError) as exc_info:
172175
parse_one("SELECT CASE FROM table")
173-
except ParseError as e:
174-
assert is_sql_parse_error(e) is True
176+
assert is_sql_parse_error(exc_info.value) is True
175177

176178
def test_is_sql_parse_error_non_sql_exception(self):
177179
"""Test that non-SQL exceptions are not detected as SQL errors."""
@@ -203,13 +205,17 @@ def __init__(self, sql_statement: str):
203205
assert len(error.msg) > 0
204206
assert "nonexistent_table" in error.msg
205207
# Hint field should exist (may be None for this error)
206-
assert hasattr(error, 'hint')
208+
assert hasattr(error, "hint")
207209

208210
def test_create_sql_error_long_statement(self):
209211
"""Test SQL statement truncation in error creation."""
210212
import duckdb
211213

212-
long_statement = "SELECT " + ", ".join([f"col_{i}" for i in range(100)]) + " FROM test"
214+
long_statement = (
215+
"SELECT "
216+
+ ", ".join([f"col_{i}" for i in range(100)])
217+
+ " FROM test"
218+
)
213219

214220
class MockCell:
215221
def __init__(self, sql_statement: str):
@@ -244,7 +250,7 @@ def test_extract_sql_position_sqlglot_format(self):
244250
sqlglot_msg = "Parse error at line 2, col 10"
245251
line, col = extract_sql_position(sqlglot_msg)
246252
assert line == 1 # 0-based
247-
assert col == 9 # 0-based
253+
assert col == 9 # 0-based
248254

249255
def test_extract_sql_position_no_position(self):
250256
"""Test position extraction when no position info available."""
@@ -266,10 +272,13 @@ class MockCell:
266272
except Exception as e:
267273
error = create_sql_error_from_exception(e, MockCell())
268274
# Should have "SQL syntax error:" prefix for ParserException
269-
assert error.msg.startswith("SQL syntax error:") or error.msg.startswith("SQL parse error:")
275+
assert error.msg.startswith(
276+
"SQL syntax error:"
277+
) or error.msg.startswith("SQL parse error:")
270278

271279
def test_error_message_cleaning(self):
272280
"""Test that error messages are cleaned of traces."""
281+
273282
class MockException(Exception):
274283
def __str__(self):
275284
return "SQL error message\nTraceback (most recent call last):\n File..."
@@ -299,6 +308,7 @@ def test_sql_function_error_flow(self):
299308

300309
def test_empty_sql_statement_error_handling(self):
301310
"""Test error handling with empty SQL statements."""
311+
302312
class MockCell:
303313
sqls = []
304314

@@ -309,11 +319,14 @@ class MockCell:
309319

310320
def test_cell_without_sqls_attribute(self):
311321
"""Test error handling when cell doesn't have sqls attribute."""
322+
312323
class MockCellNoSqls:
313324
pass
314325

315326
mock_exception = Exception("Test error")
316-
error = create_sql_error_from_exception(mock_exception, MockCellNoSqls())
327+
error = create_sql_error_from_exception(
328+
mock_exception, MockCellNoSqls()
329+
)
317330

318331
assert error.sql_statement == ""
319332

@@ -339,52 +352,70 @@ def test_duckdb_hints_preserved(self):
339352
import duckdb
340353

341354
# Create a table to generate "Did you mean?" suggestions
342-
duckdb.sql("CREATE OR REPLACE TABLE test_hints_table (id INT, name TEXT)")
355+
duckdb.sql(
356+
"CREATE OR REPLACE TABLE test_hints_table (id INT, name TEXT)"
357+
)
343358

344359
with pytest.raises(MarimoSQLException) as exc_info:
345360
sql("SELECT * FROM test_hint") # Missing 's' in table name
346361

347-
error_msg = str(exc_info.value)
348-
# Check that both the error and hint are present
362+
error = exc_info.value
363+
error_msg = str(error)
364+
# Check that the main error message is present
349365
assert "does not exist" in error_msg
350-
assert ("Did you mean" in error_msg or "candidate" in error_msg.lower())
366+
# Check that the hint is properly extracted to the hint field
367+
assert error.hint is not None
368+
assert (
369+
"Did you mean" in error.hint or "candidate" in error.hint.lower()
370+
)
351371

352372
@pytest.mark.skipif(not HAS_DUCKDB, reason="DuckDB not installed")
353373
def test_column_candidates_preserved(self):
354374
"""Test that column candidate hints are preserved in error messages."""
355375
import duckdb
356376

357377
# Create a table to generate candidate binding suggestions
358-
duckdb.sql("CREATE OR REPLACE TABLE test_columns (id INT, user_name TEXT, email TEXT)")
378+
duckdb.sql(
379+
"CREATE OR REPLACE TABLE test_columns (id INT, user_name TEXT, email TEXT)"
380+
)
359381

360382
with pytest.raises(MarimoSQLException) as exc_info:
361383
sql("SELECT fullname FROM test_columns") # Wrong column name
362384

363-
error_msg = str(exc_info.value)
364-
# Check that candidate bindings are included
385+
error = exc_info.value
386+
error_msg = str(error)
387+
# Check that the main error message is present
365388
assert "not found" in error_msg
366-
assert ("Candidate" in error_msg or "candidate" in error_msg.lower())
389+
# Check that the hint is properly extracted to the hint field
390+
assert error.hint is not None
391+
assert "Candidate" in error.hint or "candidate" in error.hint.lower()
367392

368393
@pytest.mark.skipif(not HAS_DUCKDB, reason="DuckDB not installed")
369394
def test_hint_field_in_sql_error_struct(self):
370395
"""Test that MarimoSQLError struct properly includes hint field."""
371396
import duckdb
372397

373398
# Create table for hint generation
374-
duckdb.sql("CREATE OR REPLACE TABLE hint_test_table (id INT, name TEXT)")
399+
duckdb.sql(
400+
"CREATE OR REPLACE TABLE hint_test_table (id INT, name TEXT)"
401+
)
375402

376403
try:
377404
duckdb.sql("SELECT * FROM hint_test") # Missing letters
378405
except Exception as e:
406+
379407
class MockCell:
380408
sqls = ["SELECT * FROM hint_test"]
381409

382410
error_struct = create_sql_error_from_exception(e, MockCell())
383411

384412
# Verify the struct has the hint field and it's populated
385-
assert hasattr(error_struct, 'hint')
413+
assert hasattr(error_struct, "hint")
386414
assert error_struct.hint is not None
387-
assert ("Did you mean" in error_struct.hint or "candidate" in error_struct.hint.lower())
415+
assert (
416+
"Did you mean" in error_struct.hint
417+
or "candidate" in error_struct.hint.lower()
418+
)
388419
# Main message should not contain the hint
389420
assert error_struct.hint not in error_struct.msg
390421

@@ -394,18 +425,23 @@ def test_multiline_hints_preserved(self):
394425
import duckdb
395426

396427
# Create table for multiline hint generation
397-
duckdb.sql("CREATE OR REPLACE TABLE hint_multiline_table (id INT, name TEXT)")
428+
duckdb.sql(
429+
"CREATE OR REPLACE TABLE hint_multiline_table (id INT, name TEXT)"
430+
)
398431

399432
try:
400-
duckdb.sql("SELECT SUBSTRING(name) FROM hint_multiline_table") # Wrong args
433+
duckdb.sql(
434+
"SELECT SUBSTRING(name) FROM hint_multiline_table"
435+
) # Wrong args
401436
except Exception as e:
437+
402438
class MockCell:
403439
sqls = ["SELECT SUBSTRING(name) FROM hint_multiline_table"]
404440

405441
error_struct = create_sql_error_from_exception(e, MockCell())
406442

407443
# Verify multiline hint is captured completely
408-
assert hasattr(error_struct, 'hint')
444+
assert hasattr(error_struct, "hint")
409445
assert error_struct.hint is not None
410446
assert "Candidate functions:" in error_struct.hint
411447
assert "substring(VARCHAR, BIGINT, BIGINT)" in error_struct.hint

0 commit comments

Comments
 (0)