Почему я получаю KeyError: "Настройки Django не определяют RESOLVER"?
Я получаю ошибку ниже:
(testassets) ➜ testassets git: (master) ✗ django-admin.py test Создание тестовой базы данных для псевдонима 'default'... E =================================================================================== ОШИБКА: test_get_site_root_with_settings_overrides (app.tests.AssetsTestCase) ---------------------------------------------------------------------- Traceback (последний вызов был последним): Файл "/Volumes/fifteen5cs/testassets/app/tests.py", строка 27, в файле test_get_site_root_with_settings_overrides http_client.get('/')"/Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages/django/test/client.py", строка 473, в файле get response = super(Client, self).get(path, data=data, **extra) Файл "/Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages/django /test/client.py ", строка 280, в файле get return self.request(**r)" /Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages/django/test/ client.py ", строка 444, в файле запроса six.reraise(*exc_info)"/Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages/django/core/handlers/base.py", строка 114, в get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) Файл"/Volumes/fifteen5cs/testassets/app/views.py", строка 9, в индексе context_instance=RequestContext(request)) Файл" /Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages/django/shortcuts/init.py ", строка 29, в render_to_response вернуть HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs) файл "/Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages/django/template/loader.py", строка 169, в render_to_string возвращает файл t.render(context_instance)"/Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages/django/template/base.py", строка 140, при рендеринге, возвращает self._render(контекст) Файл "/Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages/django/test/utils.py", строка 85, в instrumented_test_render вернуть файл self.nodelist.render(context) "/Users/paul/.pyenv/versions/te stassets / lib / python2.7 / site-packages / django / template / base.py ", строка 840, в файле рендеринга bit = self.render_node(node, context) Файл"/Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages/django/template/debug.py", строка 78, в render_node, вернуть файл node.render(context), файл"/Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages/django_assets/templatetags/assets.py", строка 72, в рендере для URL в bundle.urls(): файл"/Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages/webassets/bundle.py", строка 783, в URL для bundle, extra_filters, new_ctx в self.iterbuild(ctx): Файл"/Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages/webassets/bundle.py", строка 679, в iterbuild для пакета, _ в self.resolve_contents(ctx): Файл" /Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages/ webassets / bundle.py ", строка 233, в файле resol_contents result = ctx.resolver.resolve_source(ctx, item)" /Users/paul/.pyenv/versions/testassets/lib/python2.7/sit Электронные пакеты / webassets / bundle.py ", строка 50, в getattr возвращают файл self.getattr(self._parent, item)" /Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages /webassets/bundle.py ", строка 58, в getattr вернуть файл getattr (объект, элемент)"/Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages/webassets/env.py", строка 675, в _get_resolver возвращает файл self._storage['resolver]] "/Users/paul/.pyenv/versions/testassets/lib/python2.7/site-packages/django_assets/env.py", строка 62, в getitem self._transform_key (key)) KeyError: "Настройки Django не определяют RESOLVER"
----------------------------------------------------------------------
Ran 1 test in 0.325s
FAILED (errors=1)
Destroying test database for alias 'default'...
Я частично связал эту ошибку с использованием функции утилит Django django.test.utils.override_settings
в рамках одного из моих модульных тестов (показано ниже)
1 from django.test.utils import override_settings
2 from django.utils.unittest.case import TestCase
3 from django.test.client import Client
4
5
6 OVERRIDE_SETTINGS = {
7 'DEBUG': True,
8 'ASSETS_DEBUG': True,
9 'ASSETS_AUTO_BUILD': True,
10 'ASSETS_URL_EXPIRE': False,
11 'ASSETS_CACHE': False,
12 'ASSETS_MANIFEST': False,
13 'ASSETS_VERSIONS': False,
14 }
15
16
17 class AssetsTestCase(TestCase):
18 def test_get_site_root_with_settings_overrides(self):
19 http_client = Client()
20 # import pdb;pdb.set_trace()
21 settings_override = override_settings(**OVERRIDE_SETTINGS)
22 settings_override.enable()
23 http_client.get('/')
24 settings_override.disable()
25
26 settings_override.enable()
27 http_client.get('/')
28 settings_override.disable()
(NB. Исключение возникает во время второго запроса!)
Кодовая база, над которой я работаю, впервые представившая эту проблему, слишком велика и закрыта для совместного использования, поэтому я сократил проект до небольшого количества кода, который все еще создает проблему. Этот мини-проект можно найти здесь https://github.com/logston/testassets.
Я потратил более двух дней, пытаясь определить, откуда именно эта ошибка и почему она возникает во время второго запроса, но не первого. Я попробовал несколько перестановок модульных тестов. Интересно, что если я создаю второй модульный тест, который не включает переопределения параметров (например, как показано ниже) и назову этот тест таким, чтобы он выполнялся первым во время тестирования, набор тестов будет пройден. Если я поставлю тот же модульный тест после test_get_site_root_with_settings_overrides
модульный тест, оба не пройдут.
def test_get_site_root(self):
http_client = Client()
http_client.get('/')
http_client.get('/')
Любая помощь в этом вопросе будет очень признательна.
Наконец, единственная проблема, которую я могу найти, которая говорит о той же или подобной проблеме, находится здесь: https://github.com/miracle2k/django-assets/issues/44
ОБНОВЛЕНИЕ 2015/01/12
Похоже, проблема связана с использованием сигналов. Я сократил вышеупомянутый провальный тест до следующего:
from django.test.utils import override_settings
from django.utils.unittest.case import TestCase
from django_assets.env import get_env
class AssetsTestCase(TestCase):
def test(self):
settings_override = override_settings()
settings_override.enable()
get_env().resolver
settings_override.disable()
settings_override.enable()
get_env().resolver
settings_override.disable()
1 ответ
Оказывается, эта проблема связана с тем, что django_assets.env.env
синглтон не сбрасывается после отключения любого override_settings
, Тот факт, что этот одноэлементный объект не перестраивается между объектами "настроек", означает, что если django_assets.env.env
Объект строится в контексте переопределенных настроек, когда эти переопределенные настройки заменяются на не переопределенные настройки, любые константы добавляются в модуль временных настроек путем создания django_assets.env.env
объект будет потерян. RESOLVER
а также ASSETS_CACHE
являются отличными примерами констант, которые будут потеряны. Чтобы избежать этой потери, мы должны обязательно сбросить django_assets.env.env
возражать django_assets.env.reset
после изменения настроек модулей. призвание reset
заставит django-assets повторно вставить эти константы обратно в модули текущих настроек в следующий раз django_assets.env.get_env
называется.
К сожалению звоню django_assets.env.reset
вызывает django_assets.env.env._bundle_names
словарь, подлежащий опустошению (примечание: он действительно уничтожен, а новый построен). Потеря этого словаря приводит к ошибкам вроде следующего:
BundleError: %s not found (using staticfiles finders)
Чтобы исправить эту проблему, мы должны обновить django_assets.env._ASSETS_LOADED
в False
и удалить каждое приложение assets.py
файл из sys.modules
, Мы должны обновить _ASSETS_LOADED
так что django-assets пытается повторно импортировать файл ресурсов каждого приложения в следующий раз django_assets.env.get_env
называется. Призыв к django_assets.env.get_env
также восстановит env._bundle_names
толковый словарь. Наконец, мы должны удалить модуль ресурсов каждого приложения из sys.modules. Иначе, __import__('app.assets')
не будет импортировать (читать 'выполнить') модуль ресурсов, потому что модуль активов уже импортирован!
Таким образом, полное решение этого вопроса будет примерно таким:
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']
Кстати, я все уши за предложения о других способах решения этой проблемы.