You make a lot of assumptions
The database file stays opened as long as the connection object exists, and is not explicitly closed.
The sqlite3 context manager does all it can to prevent leaving the database in a locked state.
After leaving the with
block there are roughly four paths for __exit__
:
- no transaction is open;
__exit__
is a no-op; no lock is held
- pending transaction, no exceptions raised; implicit commit that succeeds; no lock is held
- pending transaction, no exceptions raised; implicit commit that fails; rollback; no lock is held
- pending transaction, exception raised; implicit rollback; no lock is held
For 3. and 4., there might be a possibility that the rollback fails, but I don’t know what kind of scenario that could be. I tried to provoke such a scenario sometime last year, but I failed. I guess you’d have more serious problems than a locked database file in that case
Note that not all queries hold the database lock.
Also note, that it is possible to open a database without locking, using the uri
parameter to connect
.
I’m not sure what you mean with this. I don’t think the context manager requires the (optional) target variable to cease to exist. For example, this is a common idiom in the CPython test suite:
class Tests(unittest.TestCase):
def test_thing(self):
with self.assertWarns(DeprecationWarning) as cm:
some_deprecated_func()
self.assertEqual(cm.filename, __file__)
You can also try this in your REPL:
>>> import sqlite3
>>> with sqlite3.connect(":memory:") as cx: pass
...
>>> cx # what do you expect to see when you press enter?
No, you should not make assumtions regarding when an object is implicitly deleted. This goes for all resources, IMO, not just sqlite3 connection objects. If you want to make sure that connection cx
is closed, do it explicitly by calling cx.close()
or del cx
. Explicit is better than implicit
__del__
is not called at all by the sqlite3 context manager; the sqlite3 context manager only calls two methods: commit and rollback. It does nothing else. It does not care about the scope of the variable. It does not know about the GC. It does not know about __del__
.
I have no idea I would expect MAL to have a clue, though.
Depends on your use case. I have a short snippet that uses contextlib.closing to simplify resource management in the sqlite3 test suite. In my own code, I’ve normally used a single worker thread and a job queue, probably because I’m lazy. For other use cases, where multiple connections/cursors are expected, I’d use a simple contextlib wrapper (contextlib FTW).