Skip to content

Commit

Permalink
Merge branch 'improve-sqlite-settings'
Browse files Browse the repository at this point in the history
  • Loading branch information
epicserve committed Nov 2, 2024
2 parents 92fe623 + d279e4e commit bb7c572
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 9 deletions.
57 changes: 51 additions & 6 deletions src/dj_beat_drop/new.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
import os
import re
import shutil
import urllib.parse
from pathlib import Path
from textwrap import dedent

from InquirerPy import inquirer
from packaging.version import Version

from dj_beat_drop import utils
from dj_beat_drop.utils import color

EXTRA_SQLITE_PARAMS = {
"transaction_mode": "IMMEDIATE",
"init_command": (
"PRAGMA journal_mode = WAL;"
"PRAGMA synchronous = NORMAL;"
"PRAGMA mmap_size = 134217728;"
"PRAGMA journal_size_limit = 27103364;"
"PRAGMA cache_size = 2000"
),
}


def rename_template_files(project_dir):
# Rename .py-tpl files to .py
Expand All @@ -18,6 +32,36 @@ def rename_template_files(project_dir):
os.rename(file, file.with_name(file.name[:-4]))


def replace_sqlite_config(content: str, django_version: str) -> str:
if Version(django_version) < Version("5.1"):
return content

init_command_str = "".join(
[f' "{param};"\n' for param in EXTRA_SQLITE_PARAMS["init_command"].split(";")]
)
rtn_val = content
rtn_val = re.sub(
r"^DATABASES\s*=\s*\{.+?\}\n\}",
dedent(
"DATABASES = {\n"
" 'default': {\n"
" 'ENGINE': 'django.db.backends.sqlite3',\n"
" 'NAME': BASE_DIR / 'db.sqlite3',\n"
" 'OPTIONS': {\n"
f" 'transaction_mode': '{EXTRA_SQLITE_PARAMS['transaction_mode']}',\n"
' \'init_command\': (\n'
f'{init_command_str}'
' )\n'
" }\n"
" }\n"
"}\n"
),
rtn_val,
flags=re.MULTILINE | re.DOTALL,
)
return rtn_val


def replace_settings_with_environs(content: str) -> str:
rtn_val = content
init_env = "# Initialize environs\n" "env = Env()\n" "env.read_env()"
Expand Down Expand Up @@ -47,12 +91,11 @@ def replace_settings_with_environs(content: str) -> str:

def create_dot_envfile(project_dir, context: dict[str, str]):
env_file_path = project_dir / ".env"
env_content = (
"DEBUG=True\n"
f"SECRET_KEY=\"{context['secret_key']}\"\n"
f'ALLOWED_HOSTS=\n'
f"DATABASE_URL=sqlite:///{project_dir / 'db.sqlite3'}"
)
sqlite_url = f"sqlite:///{project_dir / 'db.sqlite3'}"
if Version(context["django_version"]) >= Version("5.1"):
sqlite_url += "?" + urllib.parse.urlencode(EXTRA_SQLITE_PARAMS)
env_content = f"DEBUG=True\nSECRET_KEY=\"{context['secret_key']}\"\nALLOWED_HOSTS=\nDATABASE_URL={sqlite_url}\n"

with open(env_file_path, "w") as f:
f.write(env_content)

Expand All @@ -68,6 +111,8 @@ def replace_variables(project_dir, context: dict[str, str], initialize_env):
if str(file.relative_to(project_dir)) == "config/settings.py" and initialize_env is True:
content = replace_settings_with_environs(content)
create_dot_envfile(project_dir, context)
if str(file.relative_to(project_dir)) == "config/settings.py" and initialize_env is False:
content = replace_sqlite_config(content, context["django_version"])
with file.open("w") as f:
f.write(content)

Expand Down
40 changes: 37 additions & 3 deletions tests/test_new_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,32 @@
import shutil
import string
from pathlib import Path
from textwrap import dedent
from unittest import TestCase

from packaging.version import Version

from dj_beat_drop.new import create_new_project

ENV_SECRET_KEY_PATTERN = 'SECRET_KEY = env.str("SECRET_KEY")' # noqa: S105
SQLITE_OPTIONS_ENV = (
"?transaction_mode=IMMEDIATE"
"&init_command=PRAGMA+journal_mode+%3D+WAL"
"%3BPRAGMA+synchronous+%3D+NORMAL"
"%3BPRAGMA+mmap_size+%3D+134217728"
"%3BPRAGMA+journal_size_limit+%3D+27103364"
"%3BPRAGMA+cache_size+%3D+2000"
)
SQLITE_OPTIONS = dedent("""
'transaction_mode': 'IMMEDIATE',
'init_command': (
"PRAGMA journal_mode = WAL;"
"PRAGMA synchronous = NORMAL;"
"PRAGMA mmap_size = 134217728;"
"PRAGMA journal_size_limit = 27103364;"
"PRAGMA cache_size = 2000;"
)
""")
FILE_ASSERTIONS = {
"manage.py": [
"os.environ.setdefault('DJANGO_SETTINGS_MODULE', '{{ project_name }}.settings')",
Expand Down Expand Up @@ -47,6 +68,8 @@
'SECRET_KEY="{{ secret_key }}"',
"ALLOWED_HOSTS=",
"DATABASE_URL=sqlite:///{{ project_dir }}/db.sqlite3",
# If Django version is 5.1 or higher, the following option should be present in the DATABASE_URL
("5.1", SQLITE_OPTIONS_ENV),
],
"config/settings.py": [
"from environs import Env",
Expand All @@ -56,6 +79,10 @@
'DATABASES = {"default": env.dj_db_url("DATABASE_URL")}',
],
}
NO_ENV_ASSERTIONS = {
# If Django version is 5.1 or higher, the following option should be present in the DATABASE_URL
"config/settings.py": [("5.1", option) for option in SQLITE_OPTIONS.splitlines()],
}


class SafeDict(dict):
Expand Down Expand Up @@ -112,20 +139,27 @@ def assert_files_are_correct(
assertions.extend(uv_assertions)
if initialize_env is True:
assertions.extend(env_assertions)
else:
assertions.extend(NO_ENV_ASSERTIONS.get(relative_path, []))
with open(file) as f:
content = f.read()
for assertion_pattern in assertions:
version_str = None
if isinstance(assertion_pattern, list | tuple) is True:
version_str, assertion_pattern = assertion_pattern
if version_str and Version(template_context["django_version"]) < Version(version_str):
continue
if (
assertion_pattern.startswith("SECRET_KEY =")
and initialize_env is True
and relative_path == "config/settings.py"
):
assertion_pattern = ENV_SECRET_KEY_PATTERN
if re.match(r".*{{\s[_a-z]+\s}}.*", assertion_pattern) is None:
assertion = assertion_pattern
else:
if re.match(r".*{{\s[_a-z]+\s}}.*", assertion_pattern):
formatted_assertion = assertion_pattern.replace("{{ ", "{").replace(" }}", "}")
assertion = formatted_assertion.format_map(SafeDict(assertion_context))
else:
assertion = assertion_pattern
assert assertion in content, f"Assertion failed for {relative_path}: {assertion}"

def test_new_command_with_defaults(self):
Expand Down

0 comments on commit bb7c572

Please sign in to comment.