Почему я получаю 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']

Кстати, я все уши за предложения о других способах решения этой проблемы.

Другие вопросы по тегам