Skip to content

Commit 58287db

Browse files
add DJANGO_CONFIGURATION_HOOK as optional parameter to allow customly configured settings instances
1 parent f27c6aa commit 58287db

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

pytest_django/plugin.py

+41
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555

5656
SETTINGS_MODULE_ENV = "DJANGO_SETTINGS_MODULE"
5757
CONFIGURATION_ENV = "DJANGO_CONFIGURATION"
58+
CONFIGURATION_HOOK_ENV = "DJANGO_CONFIGURATION_HOOK"
5859
INVALID_TEMPLATE_VARS_ENV = "FAIL_INVALID_TEMPLATE_VARS"
5960

6061
_report_header = []
@@ -98,6 +99,14 @@ def pytest_addoption(parser) -> None:
9899
default=None,
99100
help="Set DJANGO_CONFIGURATION.",
100101
)
102+
group.addoption(
103+
"--dch",
104+
action="store",
105+
type=str,
106+
dest="dch",
107+
default=None,
108+
help="Set DJANGO_CONFIGURATION_HOOK.",
109+
)
101110
group.addoption(
102111
"--nomigrations",
103112
"--no-migrations",
@@ -124,6 +133,9 @@ def pytest_addoption(parser) -> None:
124133
parser.addini(
125134
SETTINGS_MODULE_ENV, "Django settings module to use by pytest-django."
126135
)
136+
parser.addini(
137+
CONFIGURATION_HOOK_ENV, "Callback Hook to prepare Django settings alternatively."
138+
)
127139

128140
parser.addini(
129141
"django_find_project",
@@ -329,6 +341,7 @@ def _get_option_with_source(
329341

330342
ds, ds_source = _get_option_with_source(options.ds, SETTINGS_MODULE_ENV)
331343
dc, dc_source = _get_option_with_source(options.dc, CONFIGURATION_ENV)
344+
dch, dch_source = _get_option_with_source(options.dch, CONFIGURATION_HOOK_ENV)
332345

333346
if ds:
334347
_report_header.append("settings: {} (from {})".format(ds, ds_source))
@@ -349,6 +362,34 @@ def _get_option_with_source(
349362

350363
with _handle_import_error(_django_project_scan_outcome):
351364
dj_settings.DATABASES
365+
elif dch:
366+
# Forcefully load Django settings, throws ImportError or
367+
# ImproperlyConfigured if settings cannot be loaded.
368+
from django.conf import settings as dj_settings
369+
370+
# Call a HOOK that could initialize djangos
371+
# object with a custom configuration
372+
373+
if "." not in dch:
374+
raise ImportError(f"Invalid path for configuration hook: {dch}")
375+
376+
pkg_parts = dch.split(".")
377+
module_path = ".".join(pkg_parts[:-1])
378+
function_name = pkg_parts[-1]
379+
380+
import importlib
381+
382+
try:
383+
mod = importlib.import_module(module_path)
384+
except (ImportError, AttributeError):
385+
raise ImportError(f"Unable to import module {module_path}")
386+
func = getattr(mod, function_name, None)
387+
388+
if not func:
389+
raise ImportError(f"No function found with name {function_name} in module {module_path}!")
390+
391+
# Call the function
392+
func()
352393

353394
_setup_django()
354395

tests/test_django_settings_module.py

+29
Original file line numberDiff line numberDiff line change
@@ -505,3 +505,32 @@ def test_no_django_settings_but_django_imported(testdir, monkeypatch) -> None:
505505
testdir.makeconftest("import django")
506506
r = testdir.runpytest_subprocess("--help")
507507
assert r.ret == 0
508+
509+
510+
def test_dch_ini(testdir, monkeypatch) -> None:
511+
monkeypatch.delenv("DJANGO_SETTINGS_MODULE")
512+
testdir.makeini(
513+
"""
514+
[pytest]
515+
DJANGO_CONFIGURATION_HOOK = tpkg.test.setup
516+
"""
517+
)
518+
pkg = testdir.mkpydir("tpkg")
519+
pkg.join("test.py").write(
520+
"""
521+
# Test
522+
from django.conf import settings
523+
524+
def setup():
525+
settings.configure()
526+
""")
527+
testdir.makepyfile(
528+
"""
529+
import os
530+
531+
def test_ds():
532+
pass
533+
"""
534+
)
535+
result = testdir.runpytest_subprocess()
536+
assert result.ret == 0

0 commit comments

Comments
 (0)