Skip to content

Commit b30819e

Browse files
authored
Merge pull request #130 from JeffersonLab/claude/ci-failure-investigation-blw13n
Dispose DB engine in CLI to fix Python 3.13 ResourceWarning leak
2 parents 9c202a2 + 69ef216 commit b30819e

3 files changed

Lines changed: 30 additions & 2 deletions

File tree

python/rcdb/app_context.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@ def db(self) -> RCDBProvider:
1919
self._db_instance = RCDBProvider(self.connection_str)
2020
return self._db_instance
2121

22+
def close(self):
23+
"""Disconnect the database if one was opened.
24+
25+
Safe to call when no connection was ever made. The CLI registers this on
26+
the Click context so the engine is disposed deterministically when the
27+
command finishes, instead of waiting for garbage collection (which on
28+
Python 3.13+ leaks a ``ResourceWarning: unclosed database``).
29+
"""
30+
if self._db_instance is not None:
31+
self._db_instance.disconnect()
32+
self._db_instance = None
33+
2234
def require_connected_db(self) -> RCDBProvider:
2335
"""Return the RCDBProvider, or fail with a clear CLI error if no connection was given.
2436

python/rcdb/cli/app.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ def rcdb_cli(ctx, user_config, connection, config, verbose):
6060
for key, value in config:
6161
ctx.obj.set_config(key, value)
6262

63+
# Dispose the DB engine deterministically when the command finishes, rather
64+
# than leaving it to garbage collection. On Python 3.13+ a lingering, GC'd
65+
# SQLite connection emits "ResourceWarning: unclosed database" at an
66+
# unpredictable time, which can leak into command output captured by tests.
67+
ctx.call_on_close(ctx.obj.close)
68+
6369
# Bo commands given
6470
if ctx.invoked_subcommand is None:
6571
# There is a connection but no subcommand

python/rcdb/provider.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,19 @@ def connect(self, connection_string="mysql+pymysql://rcdb@127.0.0.1/rcdb", check
150150
# Closes connection to data
151151
# ------------------------------------------------
152152
def disconnect(self):
153-
"""Closes connection to database"""
153+
"""Closes connection to database.
154+
155+
Closes the ORM session and disposes the SQLAlchemy engine so the
156+
underlying connection pool releases its DBAPI connections. Without the
157+
``engine.dispose()`` the pooled SQLite/MySQL connection stays open until
158+
the engine is garbage collected, which on Python 3.13+ surfaces as a
159+
``ResourceWarning: unclosed database`` at an unpredictable time.
160+
"""
154161
self._is_connected = False
155-
self.session.close()
162+
if self.session is not None:
163+
self.session.close()
164+
if self.engine is not None:
165+
self.engine.dispose()
156166

157167
# -------------------------------------------------
158168
# indicates ether the connection is open or not

0 commit comments

Comments
 (0)