diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-12-17 01:17:48 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-12-17 01:17:48 +0000 |
| commit | 5babbaf48a71af786d41f59a1f1f7d5272a60a4d (patch) | |
| tree | 4c3c4264e73410db07baffaebd879b36c4ae5aed | |
| parent | 0bf2866211d095a18a5c61d7af644c8e17486e6e (diff) | |
| download | pyramid-5babbaf48a71af786d41f59a1f1f7d5272a60a4d.tar.gz pyramid-5babbaf48a71af786d41f59a1f1f7d5272a60a4d.tar.bz2 pyramid-5babbaf48a71af786d41f59a1f1f7d5272a60a4d.zip | |
- When Chameleon page or text templates were added imperatively (via
``Configurator.add_view`` or some derivative), they too-eagerly
attempted to look up the ``reload_templates`` setting via
``get_settings``, meaning they were always registered in
non-auto-reload-mode (the default). Each now waits until its
respective ``template`` attribute is accessed to look up the value.
| -rw-r--r-- | CHANGES.txt | 7 | ||||
| -rw-r--r-- | repoze/bfg/chameleon_text.py | 7 | ||||
| -rw-r--r-- | repoze/bfg/chameleon_zpt.py | 9 | ||||
| -rw-r--r-- | repoze/bfg/decorator.py | 15 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_chameleon_text.py | 7 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_chameleon_zpt.py | 7 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_decorator.py | 23 |
7 files changed, 73 insertions, 2 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index d84e8cb7f..10bc39389 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,6 +4,13 @@ Next release Bug Fixes --------- +- When Chameleon page or text templates were added imperatively (via + ``Configurator.add_view`` or some derivative), they too-eagerly + attempted to look up the ``reload_templates`` setting via + ``get_settings``, meaning they were always registered in + non-auto-reload-mode (the default). Each now waits until its + respective ``template`` attribute is accessed to look up the value. + - When a route with the same name as a previously registered route was added, the old route was not removed from the mapper's routelist. Symptom: the old registered route would be used (and possibly diff --git a/repoze/bfg/chameleon_text.py b/repoze/bfg/chameleon_text.py index 50491a3d0..9cb1c989a 100644 --- a/repoze/bfg/chameleon_text.py +++ b/repoze/bfg/chameleon_text.py @@ -20,6 +20,7 @@ except ImportError: # pragma: no cover from repoze.bfg.interfaces import IResponseFactory from repoze.bfg.interfaces import ITemplateRenderer +from repoze.bfg.decorator import reify from repoze.bfg.renderers import template_renderer_factory from repoze.bfg.settings import get_settings from repoze.bfg.threadlocal import get_current_registry @@ -40,9 +41,13 @@ def renderer_factory(path): class TextTemplateRenderer(object): implements(ITemplateRenderer) def __init__(self, path): + self.path = path + + @reify + def template(self): settings = get_settings() auto_reload = settings and settings['reload_templates'] - self.template = TextTemplateFile(path, auto_reload=auto_reload) + return TextTemplateFile(self.path, auto_reload=auto_reload) def implementation(self): return self.template diff --git a/repoze/bfg/chameleon_zpt.py b/repoze/bfg/chameleon_zpt.py index bc1a5d22f..9083ff3f7 100644 --- a/repoze/bfg/chameleon_zpt.py +++ b/repoze/bfg/chameleon_zpt.py @@ -13,6 +13,7 @@ except ImportError, why: # pragma: no cover from repoze.bfg.interfaces import IResponseFactory from repoze.bfg.interfaces import ITemplateRenderer +from repoze.bfg.decorator import reify from repoze.bfg.renderers import template_renderer_factory from repoze.bfg.settings import get_settings from repoze.bfg.threadlocal import get_current_registry @@ -23,9 +24,15 @@ def renderer_factory(path): class ZPTTemplateRenderer(object): implements(ITemplateRenderer) def __init__(self, path): + self.path = path + + @reify + def template(self): + # delay template creation until (hopefully) settings have been + # registered settings = get_settings() auto_reload = settings and settings['reload_templates'] - self.template = PageTemplateFile(path, auto_reload=auto_reload) + return PageTemplateFile(self.path, auto_reload=auto_reload) def implementation(self): return self.template diff --git a/repoze/bfg/decorator.py b/repoze/bfg/decorator.py new file mode 100644 index 000000000..69c1e65e2 --- /dev/null +++ b/repoze/bfg/decorator.py @@ -0,0 +1,15 @@ +class reify(object): + + """ Put the result of a method which uses this (non-data) + descriptor decorator in the instance dict after the first call, + effectively replacing the decorator with an instance variable.""" + + def __init__(self, wrapped): + self.wrapped = wrapped + + def __get__(self, inst, objtype=None): + if inst is None: + return self + val = self.wrapped(inst) + setattr(inst, self.wrapped.__name__, val) + return val diff --git a/repoze/bfg/tests/test_chameleon_text.py b/repoze/bfg/tests/test_chameleon_text.py index 54ffc8b10..007c102e3 100644 --- a/repoze/bfg/tests/test_chameleon_text.py +++ b/repoze/bfg/tests/test_chameleon_text.py @@ -47,6 +47,13 @@ class TextTemplateRendererTests(Base, unittest.TestCase): from repoze.bfg.interfaces import ITemplateRenderer verifyClass(ITemplateRenderer, self._getTargetClass()) + def test_template_reified(self): + minimal = self._getTemplatePath('minimal.txt') + instance = self._makeOne(minimal) + self.failIf('template' in instance.__dict__) + template = instance.template + self.assertEqual(template, instance.__dict__['template']) + def test_call(self): minimal = self._getTemplatePath('minimal.txt') instance = self._makeOne(minimal) diff --git a/repoze/bfg/tests/test_chameleon_zpt.py b/repoze/bfg/tests/test_chameleon_zpt.py index 38ef543cf..e4bf8f766 100644 --- a/repoze/bfg/tests/test_chameleon_zpt.py +++ b/repoze/bfg/tests/test_chameleon_zpt.py @@ -48,6 +48,13 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase): self.assertEqual(result, '<div xmlns="http://www.w3.org/1999/xhtml">\n</div>') + def test_template_reified(self): + minimal = self._getTemplatePath('minimal.pt') + instance = self._makeOne(minimal) + self.failIf('template' in instance.__dict__) + template = instance.template + self.assertEqual(template, instance.__dict__['template']) + def test_call_with_nondict_value(self): minimal = self._getTemplatePath('minimal.pt') instance = self._makeOne(minimal) diff --git a/repoze/bfg/tests/test_decorator.py b/repoze/bfg/tests/test_decorator.py new file mode 100644 index 000000000..b1ac2252d --- /dev/null +++ b/repoze/bfg/tests/test_decorator.py @@ -0,0 +1,23 @@ +import unittest + +class TestReify(unittest.TestCase): + def _makeOne(self, wrapped): + from repoze.bfg.decorator import reify + return reify(wrapped) + + def test___get__withinst(self): + def wrapped(inst): + return 'a' + decorator = self._makeOne(wrapped) + inst = Dummy() + result = decorator.__get__(inst) + self.assertEqual(result, 'a') + self.assertEqual(inst.__dict__['wrapped'], 'a') + + def test___get__noinst(self): + decorator = self._makeOne(None) + result = decorator.__get__(None) + self.assertEqual(result, decorator) + +class Dummy(object): + pass |
