I’m not sure if I’ve hit a bug or I’m holding it wrong. In my project I use a custom test runner which overrides a few Django settings (adds MD5 password hasher to PASSWORD_HASHERS for speed, stuff like that).
The test suite runs fine both sequentially and in parallel on Python 3.12. It also runs fine sequentially on Python 3.14. But when running in parallel on Python 3.14 it appears as if Django doesn’t see the settings I’ve set in the custom test runner.
A minimal reproducer:
create a new project with django-admin startproject fooproject
create two files with identical contents, fooproject/tests.py and fooproject/tests_more.py
Contents for both files:
from django.conf import settings
from django.test import TestCase
from django.test.runner import DiscoverRunner
class MyRunner(DiscoverRunner):
def setup_test_environment(self):
settings.WORLD = "World"
super().setup_test_environment()
class MyTestCase(TestCase):
def test_it_works(self):
print(f"Hello {settings.WORLD}")
Run tests like so:
./manage.py test --parallel --testrunner fooproject.tests.MyRunner
This works on Python 3.12 (prints out “Hello World” twice), but on Python 3.14, produces an error: AttributeError: 'Settings' object has no attribute 'WORLD'
As Carlton points out, what you’re trying to do is not supported.
But fwiw, DiscoverTestRunner.setup_test_environment() modifies settings in almost exactly the same way you are, so I wouldn’t expect the behavior you’re seeing. The one difference is it reads a setting before trying to write any. My best guess would be that LazySettings.__setattr__() doesn’t bootstrap settings like __getattr__() does, and that’s somehow causing confusion. You might try swapping the order of the super call and your settings override. (Also, if you’re modifying settings in setup_test_environment(), it’s good practice to restore them in teardown_test_environment(). Again, though, all of this is undocumented internals and likely to break unexpectedly.)
Also fwiw, here’s what I use to do similar test overrides, either directly in settings.py or in manage.py to swap in a test settings file. (And this approach is supported, or at least is recommended by a knowledgable Django developer.):
I didn’t get it to work by switching things around in setup_test_environment() so I moved the test-specific settings overrides to settings.pyunder an if clause and that works