Skip to content

Commit

Permalink
Tests now close SQLite database connections and files explicitly, refs
Browse files Browse the repository at this point in the history
…#1843

Also added a db.close() method to the Database class.
  • Loading branch information
simonw committed Nov 3, 2022
1 parent bb030ba commit 2355067
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 5 deletions.
11 changes: 10 additions & 1 deletion datasette/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ def __init__(
# These are used when in non-threaded mode:
self._read_connection = None
self._write_connection = None
# This is used to track all file connections so they can be closed
self._all_file_connections = []

@property
def cached_table_counts(self):
Expand Down Expand Up @@ -91,9 +93,16 @@ def connect(self, write=False):
assert not (write and not self.is_mutable)
if write:
qs = ""
return sqlite3.connect(
conn = sqlite3.connect(
f"file:{self.path}{qs}", uri=True, check_same_thread=False
)
self._all_file_connections.append(conn)
return conn

def close(self):
# Close all connections - useful to avoid running out of file handles in tests
for connection in self._all_file_connections:
connection.close()

async def execute_write(self, sql, params=None, block=True):
def _inner(conn):
Expand Down
7 changes: 7 additions & 0 deletions docs/internals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,13 @@ If your function raises an exception that exception will be propagated up to the

If you specify ``block=False`` the method becomes fire-and-forget, queueing your function to be executed and then allowing your code after the call to ``.execute_write_fn()`` to continue running while the underlying thread waits for an opportunity to run your function. A UUID representing the queued task will be returned. Any exceptions in your code will be silently swallowed.

.. _database_close:

db.close()
----------

Closes all of the open connections to file-backed databases. This is mainly intended to be used by large test suites, to avoid hitting limits on the number of open files.

.. _internals_database_introspection:

Database introspection
Expand Down
10 changes: 6 additions & 4 deletions tests/fixtures.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from datasette.app import Datasette
from datasette.utils.sqlite import sqlite3, sqlite_version
from datasette.utils.sqlite import sqlite3
from datasette.utils.testing import TestClient
import click
import contextlib
Expand All @@ -9,11 +9,9 @@
import pathlib
import pytest
import random
import sys
import string
import tempfile
import textwrap
import time


# This temp file is used by one of the plugin config tests
Expand Down Expand Up @@ -167,7 +165,11 @@ def make_app_client(
crossdb=crossdb,
)
yield TestClient(ds)
os.remove(filepath)
# Close as many database connections as possible
# to try and avoid too many open files error
for db in ds.databases.values():
if not db.is_memory:
db.close()


@pytest.fixture(scope="session")
Expand Down

0 comments on commit 2355067

Please sign in to comment.