Skip to content

Commit 33c3f53

Browse files
Cycle 11: apply ruff --fix; contextlib.suppress over try/except/pass
Extending linting to the full project (run-tests.sh previously only linted the wire package) surfaced import ordering drift, SIM105 try/except/pass patterns, and SIM201 negated equality in tests. Applied the auto-fixes (including --unsafe-fixes) and manually rewrote the three remaining SIM105 sites in connection.py and aio/connection.py to contextlib.suppress for readability. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 0d1944e commit 33c3f53

11 files changed

+47
-58
lines changed

src/dqlitedbapi/aio/connection.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Async connection implementation for dqlite."""
22

33
import asyncio
4+
import contextlib
45
from typing import Any
56

67
from dqliteclient import DqliteConnection
@@ -159,9 +160,7 @@ def cursor(self) -> AsyncCursor:
159160

160161
def __repr__(self) -> str:
161162
state = "closed" if self._closed else ("connected" if self._async_conn else "unused")
162-
return (
163-
f"<AsyncConnection address={self._address!r} database={self._database!r} {state}>"
164-
)
163+
return f"<AsyncConnection address={self._address!r} database={self._database!r} {state}>"
165164

166165
async def __aenter__(self) -> "AsyncConnection":
167166
await self.connect()
@@ -175,9 +174,7 @@ async def __aexit__(self, exc_type: type[BaseException] | None, *args: Any) -> N
175174
if exc_type is None:
176175
await self.commit()
177176
else:
178-
try:
179-
await self.rollback()
180-
except Exception:
181-
pass # Body's exception wins.
177+
with contextlib.suppress(Exception):
178+
await self.rollback() # Body's exception wins.
182179
finally:
183180
await self.close()

src/dqlitedbapi/connection.py

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,25 +29,21 @@ def _cleanup_loop_thread(
2929
if closed_flag[0] is False:
3030
# User never called close() → leak warning (matches stdlib
3131
# sqlite3). Don't crash at interpreter shutdown.
32-
try:
32+
with contextlib.suppress(Exception):
3333
warnings.warn(
3434
f"Connection(address={address!r}) was garbage-collected "
3535
f"without close(); cleaning up event-loop thread. Call "
3636
f"Connection.close() explicitly to avoid this warning.",
3737
ResourceWarning,
3838
stacklevel=2,
3939
)
40-
except Exception:
41-
pass
4240
try:
4341
if not loop.is_closed():
4442
loop.call_soon_threadsafe(loop.stop)
4543
except Exception:
4644
pass
47-
try:
45+
with contextlib.suppress(Exception):
4846
thread.join(timeout=5)
49-
except Exception:
50-
pass
5147
try:
5248
if not loop.is_closed():
5349
loop.close()
@@ -170,13 +166,12 @@ def _run_sync(self, coro: Any) -> Any:
170166
# half-written a request; the wire is in unknown state.
171167
# Fire-and-forget on the loop thread (don't await).
172168
if self._async_conn is not None:
173-
try:
169+
# RuntimeError if the loop is already shutting down.
170+
with contextlib.suppress(RuntimeError):
174171
loop.call_soon_threadsafe(
175172
self._async_conn._invalidate,
176173
OperationalError(f"sync timeout after {self._timeout}s"),
177174
)
178-
except RuntimeError:
179-
pass # loop already shutting down
180175
raise OperationalError(f"Operation timed out after {self._timeout} seconds") from e
181176

182177
async def _get_async_connection(self) -> DqliteConnection:
@@ -306,9 +301,7 @@ def cursor(self) -> Cursor:
306301

307302
def __repr__(self) -> str:
308303
state = "closed" if self._closed else ("connected" if self._async_conn else "unused")
309-
return (
310-
f"<Connection address={self._address!r} database={self._database!r} {state}>"
311-
)
304+
return f"<Connection address={self._address!r} database={self._database!r} {state}>"
312305

313306
def __enter__(self) -> "Connection":
314307
return self
@@ -328,9 +321,7 @@ def __exit__(self, exc_type: type[BaseException] | None, *args: Any) -> None:
328321
# Body already raised; attempt rollback but don't mask
329322
# the original exception. If rollback itself fails, its
330323
# error is attached via __context__ automatically.
331-
try:
324+
with contextlib.suppress(Exception):
332325
self.rollback()
333-
except Exception:
334-
pass # Body's exception wins; rollback failure is attached as context.
335326
finally:
336327
self.close()

src/dqlitedbapi/cursor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
from typing import TYPE_CHECKING, Any
55

66
import dqliteclient.exceptions as _client_exc
7-
from dqlitewire.constants import ValueType
8-
97
from dqlitedbapi.exceptions import (
108
DataError,
119
InterfaceError,
@@ -20,6 +18,7 @@
2018
_datetime_from_iso8601,
2119
_datetime_from_unixtime,
2220
)
21+
from dqlitewire.constants import ValueType
2322

2423

2524
async def _call_client(coro: Coroutine[Any, Any, Any]) -> Any:
@@ -49,6 +48,7 @@ async def _call_client(coro: Coroutine[Any, Any, Any]) -> Any:
4948
except _client_exc.InterfaceError as e:
5049
raise _DbapiInterfaceError(str(e)) from e
5150

51+
5252
if TYPE_CHECKING:
5353
from dqlitedbapi.connection import Connection
5454

tests/integration/test_datetime_conversion.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
import datetime
1111

1212
import pytest
13-
from dqlitewire.constants import ValueType
1413

1514
from dqlitedbapi import connect
1615
from dqlitedbapi.aio.connection import AsyncConnection
16+
from dqlitewire.constants import ValueType
1717

1818

1919
@pytest.mark.integration
@@ -29,7 +29,9 @@ def test_naive_datetime_stays_naive(self, cluster_address: str) -> None:
2929
dt = datetime.datetime(2024, 1, 15, 10, 30, 45) # noqa: DTZ001 - naive is the point
3030
with connect(cluster_address, database="test_dt_naive") as conn:
3131
cursor = conn.cursor()
32-
cursor.execute("CREATE TABLE IF NOT EXISTS dt_naive (id INTEGER PRIMARY KEY, ts DATETIME)")
32+
cursor.execute(
33+
"CREATE TABLE IF NOT EXISTS dt_naive (id INTEGER PRIMARY KEY, ts DATETIME)"
34+
)
3335
cursor.execute("DELETE FROM dt_naive")
3436
cursor.execute("INSERT INTO dt_naive (ts) VALUES (?)", [dt])
3537
cursor.execute("SELECT ts FROM dt_naive")
@@ -45,7 +47,9 @@ def test_aware_datetime_preserves_offset(self, cluster_address: str) -> None:
4547
dt = datetime.datetime(2024, 6, 15, 12, 30, 45, tzinfo=tz)
4648
with connect(cluster_address, database="test_dt_aware") as conn:
4749
cursor = conn.cursor()
48-
cursor.execute("CREATE TABLE IF NOT EXISTS dt_aware (id INTEGER PRIMARY KEY, ts DATETIME)")
50+
cursor.execute(
51+
"CREATE TABLE IF NOT EXISTS dt_aware (id INTEGER PRIMARY KEY, ts DATETIME)"
52+
)
4953
cursor.execute("DELETE FROM dt_aware")
5054
cursor.execute("INSERT INTO dt_aware (ts) VALUES (?)", [dt])
5155
cursor.execute("SELECT ts FROM dt_aware")
@@ -72,7 +76,9 @@ def test_null_datetime_returns_none(self, cluster_address: str) -> None:
7276
"""NULL in a DATETIME column is None on read (not an exception)."""
7377
with connect(cluster_address, database="test_dt_null") as conn:
7478
cursor = conn.cursor()
75-
cursor.execute("CREATE TABLE IF NOT EXISTS dt_null (id INTEGER PRIMARY KEY, ts DATETIME)")
79+
cursor.execute(
80+
"CREATE TABLE IF NOT EXISTS dt_null (id INTEGER PRIMARY KEY, ts DATETIME)"
81+
)
7682
cursor.execute("DELETE FROM dt_null")
7783
cursor.execute("INSERT INTO dt_null (ts) VALUES (NULL)")
7884
cursor.execute("SELECT ts FROM dt_null")
@@ -117,7 +123,9 @@ def test_integer_value_in_datetime_column_decodes_as_datetime(
117123
epoch = int(expected.timestamp())
118124
with connect(cluster_address, database="test_unixtime") as conn:
119125
cursor = conn.cursor()
120-
cursor.execute("CREATE TABLE IF NOT EXISTS ut_test (id INTEGER PRIMARY KEY, ts DATETIME)")
126+
cursor.execute(
127+
"CREATE TABLE IF NOT EXISTS ut_test (id INTEGER PRIMARY KEY, ts DATETIME)"
128+
)
121129
cursor.execute("DELETE FROM ut_test")
122130
# Bind an int — SQLite stores it as INTEGER affinity; server then
123131
# tags the column as DQLITE_UNIXTIME on readback.
@@ -136,11 +144,11 @@ class TestDescriptionTypeCode:
136144
def test_iso8601_column_description(self, cluster_address: str) -> None:
137145
with connect(cluster_address, database="test_desc_iso") as conn:
138146
cursor = conn.cursor()
139-
cursor.execute("CREATE TABLE IF NOT EXISTS desc_iso (id INTEGER PRIMARY KEY, ts DATETIME)")
140-
cursor.execute("DELETE FROM desc_iso")
141147
cursor.execute(
142-
"INSERT INTO desc_iso (ts) VALUES (?)", ["2024-01-15 10:30:45"]
148+
"CREATE TABLE IF NOT EXISTS desc_iso (id INTEGER PRIMARY KEY, ts DATETIME)"
143149
)
150+
cursor.execute("DELETE FROM desc_iso")
151+
cursor.execute("INSERT INTO desc_iso (ts) VALUES (?)", ["2024-01-15 10:30:45"])
144152
cursor.execute("SELECT id, ts FROM desc_iso")
145153
cursor.fetchall()
146154
assert cursor.description is not None

tests/integration/test_misc_coverage.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
- ISSUE-28: multi-statement SQL is rejected with a specific error.
66
"""
77

8-
import dqliteclient.exceptions
98
import pytest
109

10+
import dqliteclient.exceptions
1111
from dqlitedbapi import connect
1212
from dqlitedbapi.exceptions import OperationalError
1313

tests/test_context_manager_exit.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
instead of disappearing.
99
"""
1010

11-
import asyncio
1211
from unittest.mock import AsyncMock
1312

1413
import pytest
@@ -31,9 +30,8 @@ def test_clean_exit_commit_failure_propagates(self) -> None:
3130
"""No body exception → commit failure surfaces, not swallowed."""
3231
conn = _make_conn_with_failing_commit()
3332
try:
34-
with pytest.raises(OperationalError, match="disk full"):
35-
with conn:
36-
pass # clean body → __exit__ calls commit, which raises
33+
with pytest.raises(OperationalError, match="disk full"), conn:
34+
pass # clean body → __exit__ calls commit, which raises
3735
finally:
3836
conn.close()
3937

@@ -45,9 +43,8 @@ def test_body_exception_wins_over_rollback_failure(self) -> None:
4543
conn = _make_conn_with_failing_commit()
4644
body_error = ValueError("user bug")
4745
try:
48-
with pytest.raises(ValueError, match="user bug"):
49-
with conn:
50-
raise body_error
46+
with pytest.raises(ValueError, match="user bug"), conn:
47+
raise body_error
5148
finally:
5249
conn.close()
5350

tests/test_exception_mapping.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
import asyncio
1010
from unittest.mock import AsyncMock, MagicMock
1111

12-
import dqliteclient.exceptions as client_exc
1312
import pytest
1413

14+
import dqliteclient.exceptions as client_exc
1515
import dqlitedbapi.exceptions as dbapi_exc
1616
from dqlitedbapi.cursor import Cursor
1717

tests/test_executemany_empty.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""executemany([]) doesn't leak stale SELECT state (ISSUE-34)."""
22

3-
from unittest.mock import AsyncMock, MagicMock
3+
from unittest.mock import MagicMock
44

55
from dqlitedbapi.cursor import Cursor
66

tests/test_gc_cleanup.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
import threading
1515
import warnings
1616

17-
import pytest
18-
1917
from dqlitedbapi.connection import Connection
2018

2119

tests/test_max_total_rows_plumbing.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
the protocol, so users can't silently end up with the default.
66
"""
77

8-
import asyncio
9-
108
from dqlitedbapi.aio.connection import AsyncConnection
119
from dqlitedbapi.connection import Connection
1210

0 commit comments

Comments
 (0)