Skip to content

Fix LiveServer for in-memory SQLite database on Django >= 3. #973

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ Donald Stufft <[email protected]>
Nicolas Delaby <[email protected]>
Daniel Hahler <https://twitter.com/blueyed>
Hasan Ramezani <[email protected]>
Michael Howitz
10 changes: 10 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
Changelog
=========

unreleased
----------

Bugfixes
^^^^^^^^

* Fix :fixture:`live_server` when using an in-memory SQLite database on
Django >= 3.0.


v4.4.0 (2021-06-06)
-------------------

Expand Down
20 changes: 12 additions & 8 deletions pytest_django/live_server_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,9 @@ def __init__(self, addr: str) -> None:
for conn in connections.all():
# If using in-memory sqlite databases, pass the connections to
# the server thread.
if (
conn.settings_dict["ENGINE"] == "django.db.backends.sqlite3"
and conn.settings_dict["NAME"] == ":memory:"
):
# Explicitly enable thread-shareability for this connection
conn.allow_thread_sharing = True
if conn.vendor == 'sqlite' and conn.is_in_memory_db():
# Explicitly enable thread-shareability for this connection.
conn.inc_thread_sharing()
connections_override[conn.alias] = conn

liveserver_kwargs["connections_override"] = connections_override
Expand All @@ -50,18 +47,25 @@ def __init__(self, addr: str) -> None:
self._live_server_modified_settings = modify_settings(
ALLOWED_HOSTS={"append": host}
)
# `_live_server_modified_settings` is enabled and disabled by
# `_live_server_helper`.

self.thread.daemon = True
self.thread.start()
self.thread.is_ready.wait()

if self.thread.error:
raise self.thread.error
error = self.thread.error
self.stop()
raise error

def stop(self) -> None:
"""Stop the server"""
# Terminate the live server's thread.
self.thread.terminate()
self.thread.join()
# Restore shared connections' non-shareability.
for conn in self.thread.connections_override.values():
conn.dec_thread_sharing()

@property
def url(self) -> str:
Expand Down
6 changes: 4 additions & 2 deletions pytest_django_test/db_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

if _settings["ENGINE"] == "django.db.backends.sqlite3" and TEST_DB_NAME is None:
TEST_DB_NAME = ":memory:"
SECOND_DB_NAME = ":memory:"
SECOND_TEST_DB_NAME = ":memory:"
else:
DB_NAME += "_inner"

Expand All @@ -25,8 +27,8 @@
# An explicit test db name was given, is that as the base name
TEST_DB_NAME = "{}_inner".format(TEST_DB_NAME)

SECOND_DB_NAME = DB_NAME + '_second' if DB_NAME is not None else None
SECOND_TEST_DB_NAME = TEST_DB_NAME + '_second' if DB_NAME is not None else None
SECOND_DB_NAME = DB_NAME + '_second' if DB_NAME is not None else None
SECOND_TEST_DB_NAME = TEST_DB_NAME + '_second' if DB_NAME is not None else None


def get_db_engine():
Expand Down
6 changes: 3 additions & 3 deletions pytest_django_test/settings_sqlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": "/should_not_be_accessed",
"NAME": ":memory:",
},
"replica": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": "/should_not_be_accessed",
"NAME": ":memory:",
"TEST": {
"MIRROR": "default",
},
},
"second": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": "/should_not_be_accessed",
"NAME": ":memory:",
},
}
8 changes: 6 additions & 2 deletions pytest_django_test/settings_sqlite_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": "/pytest_django_tests_default",
"TEST": {"NAME": _filename_default},
"TEST": {
"NAME": _filename_default,
},
},
"replica": {
"ENGINE": "django.db.backends.sqlite3",
Expand All @@ -28,6 +30,8 @@
"second": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": "/pytest_django_tests_second",
"TEST": {"NAME": _filename_second},
"TEST": {
"NAME": _filename_second,
},
},
}