Skip to content

Commit 91a6904

Browse files
authored
SELECT command with syntax error causes stack dump (#79)
* Fixes #78: select command causes crash * Don't skip DuckDB tests even if DuckDB isn't installed
1 parent 478814a commit 91a6904

3 files changed

Lines changed: 25 additions & 8 deletions

File tree

datafaker/interactive/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ def do_select(self, arg: str) -> None:
361361
try:
362362
result = connection.execute(sqlalchemy.text(query))
363363
except sqlalchemy.exc.DatabaseError as exc:
364-
self.print(self.ERROR_FAILED_SQL, exc, query)
364+
self.print(self.ERROR_FAILED_SQL, exc=exc, query=query)
365365
return
366366
row_count = result.rowcount
367367
self.print(self.ROW_COUNT_MSG, row_count)
@@ -403,7 +403,7 @@ def do_peek(self, arg: str) -> None:
403403
try:
404404
result = connection.execute(query)
405405
except sqlalchemy.exc.SQLAlchemyError as exc:
406-
self.print(self.ERROR_FAILED_SQL, exc, query)
406+
self.print(self.ERROR_FAILED_SQL, exc=exc, query=query)
407407
return
408408
self.print_table(list(result.keys()), result.fetchmany(max_peek_rows))
409409

tests/test_interactive_table.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
""" Tests for the configure-tables command. """
2-
from collections.abc import MutableMapping
2+
import re
3+
from collections.abc import MutableMapping, Sized
34
from typing import Any
45

56
from sqlalchemy import select
@@ -452,7 +453,7 @@ def test_sanity_checks_errors_only(self) -> None:
452453

453454

454455
class TrickyTests(ConfigureTablesTests):
455-
"""Testing configure-tables with the instrument.sql database."""
456+
"""Testing configure-tables with arguments that could cause SQL errors."""
456457

457458
dump_file_path = "tricky.sql"
458459
database_name = "tricky"
@@ -536,11 +537,28 @@ def test_repeated_field_does_not_throw_exception(self) -> None:
536537
"Failed to display", "/".join(m for (m, _a, _kw) in tc.messages)
537538
)
538539

540+
def assert_message_correctly_formatted(
541+
self, m: str, a: Sized, kw: dict[str, Any]
542+
) -> None:
543+
"""
544+
Assert that the ``{...}`` interpolations in ``m`` match the arguments given.
545+
546+
:param m: The message.
547+
:param a: List of positional arguments.
548+
:param kw: Dict of keyword arguments.
549+
"""
550+
interpolations = set(re.findall(r"\{([A-Za-z0-9_]+)\}", m))
551+
positions = set(range(len(a)))
552+
keywords = set(kw.keys())
553+
self.assertSetEqual(interpolations, positions | keywords)
554+
539555
def test_sql_error_does_not_throw_exception(self) -> None:
540556
"""
541557
Select with a SQL error.
542558
"""
543559
with self._get_cmd({}) as tc:
544560
tc.reset()
545561
tc.do_select("+++")
546-
self.assertIn("SQL query", "/".join(m for (m, a, kw) in tc.messages))
562+
self.assertIn("SQL query", "/".join(m for (m, _a, _kw) in tc.messages))
563+
for m, a, kw in tc.messages:
564+
self.assert_message_correctly_formatted(m, a, kw)

tests/utils.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,8 @@ class TestDuckDb(TestDatabaseBase):
173173

174174
@classmethod
175175
def skip(cls) -> str | None:
176-
if shutil.which("duckdb"):
177-
return None
178-
return "need to find 'duckdb': install DuckDB to enable"
176+
"""Return None because DuckDB always works."""
177+
return None
179178

180179
def __init__(self, *args: Any, **kwargs: Any) -> None:
181180
"""Initialize TestDuckDb"""

0 commit comments

Comments
 (0)