Open hexsprite opened 10 years ago
I am having the same issue. I have posted it on stackoverflow. @miracle2k, have you seen this before?
Turns out this issue is due to the fact that the django_assets.env.env
singleton is not reset after disabling any override_settings
. The fact that this singleton object is not rebuilt between 'settings' objects means that if a django_assets.env.env
object is built in the context of overridden settings, when those overridden settings are swapped out for the non-overridden settings, any constants added to the interim settings module by the creation of the django_assets.env.env
object will be lost. RESOLVER
and ASSETS_CACHE
are great examples of constants that will be lost. To avoid this loss, we have to be sure to reset the django_assets.env.env
object by calling django_assets.env.reset
after a change in settings modules. Calling reset
will force django-assets to reinsert these constants back into the current settings modules the next time django_assets.env.get_env
is called.
Unfortunately, calling django_assets.env.reset
causes the django_assets.env.env._bundle_names
dictionary to be emptied (nb. really its destroyed and a new one is built). The loss of this dictionary causes errors like the following:
BundleError: %s not found (using staticfiles finders)
To fix this issue, we have to update django_assets.env._ASSETS_LOADED
to False
and remove each app's assets.py
file from sys.modules
. We have to update _ASSETS_LOADED
so that django-assets attempts to reimport each app's assets file the next time django_assets.env.get_env
is called. The call to django_assets.env.get_env
will also rebuild the env._bundle_names
dictionary. Finally, we have to remove each app's assets module from sys.modules. Otherwise, __import__('app.assets')
will not import (read 'execute') the assets module because the assets module is already imported!
Thus, a complete solution to this ticket's issue would be something like the following:
import sys
from django_assets import env as assets_env
settings_override = override_settings(**OVERRIDE_SETTINGS)
settings_override.enable()
... do things ...
settings_override.disable()
assets_env.reset()
assets_env._ASSETS_LOADED = False
del sys.modules['<app_name>.assets']
What's the status of this issue. I'm (still) having the same problem after the upgrade to 0.10
Not sure. Not working on this issue anymore.
Never fixed it for myself.
Ok, well, your suggestion in my test classes after settings_override.disable() fixes my problem, though it's a bit of a hack. My thanks to you!
Also having the same problem.
+1
Advanced workaround:
Django exposes a setting_changed
signal that can be used to perform this reset. In 1.7 it's django.test.signals.setting_changed
( https://github.com/django/django/blob/1.7/django/test/signals.py#L14 ), in 1.8+ it's django.core.signals.setting_changed
( https://github.com/django/django/blob/1.8/django/core/signals.py#L6 ). You can then put this in the bottom of one of your apps.py
files:
def fix_assets(*args, **kwargs):
from django_assets import env as assets_env
assets_env.reset()
assets_env._ASSETS_LOADED = False
# Search for assets modules that need reloading - n.b. this isn't the proper way of doing it
for name in settings.INSTALLED_APPS:
assets_module = name + '.assets'
if assets_module in sys.modules:
del sys.modules[assets_module]
and then in your app config's ready()
you can connect to the signal:
class MyAppConfig(AppConfig):
def ready(self):
from django.test.signals import setting_changed
setting_changed.connect(fix_assets)
This is half the code needed to implement a proper patch - depends on the reloading though. Will have a look at writing a PR soon.
Just some preliminary thoughts:
I've had other issues with the fact that webassets wants to push the actual object instances of resolver, updater etc. to the settings object; in that case, the settings backend only supported string values.
I think the issue here is fundamentally with the design of the settings backend API. It exists, because we want integration modules like django-assets to allow configuration via the native settings systems.
If in Django, it is possible to switch out the settings objects completely, the django-assets backend needs to accommodate that. Maybe by listening to the settings_changed
signal and reapplying it's default values.
If the settings backend API of webassets core needs to be changed to make this possible, so be it. I wonder right now, for instance, if it is sound that webassets core wants to write the defaults for it's settings to the settings storage directly when the environment is created, of if it should fall back to the defaults, on access, when the settings backend does not have a value for a setting.
Every other django library I can remember looking at falls back to defaults on-access. Maybe webassets should change.
That said if you can safely re-init the enviroment object on settings_changed
, that would be simpler.
For the record, I'm still seeing this issue in Django 1.11 with django-assets==0.12
. It's only intermittent, and only seems to effect integration testing using pytest and Django's StaticLiveServerTestCase.
I will likely be adding @adamchainz's fix_assets
patch to the setUp
of my integration test base class for now. @miracle2k Are there any plans for a proper fix?
I've started getting this same error, seemingly at random, on a production server but not during testing, so the fix_assets
patch isn't relevant. It started happening on a site that has been running smoothly for over a year. I can't think of any changes to assets or settings that have happened recently. Restarting the supervisor process resolves the issue, but it's causing site-wide 500 errors until that happens. Stacktrace just points to the template level assets code. Any clue what this could be?
Using versions:
Django==2.0.8
django-assets==0.12
webassets==0.12.1
Settings:
ASSETS_DEBUG = False
ASSETS_AUTO_BUILD = False
TLDR - getting error:
KeyError: "Django settings doesn't define RESOLVER"
Have this in my requirements.txt:
django-assets==0.10 webassets==0.10.1
Django 1.6.4
When running tests I get this error:
In my test setup I use Django's
override_settings
to configure a test environment like so: