summaryrefslogtreecommitdiff
path: root/repoze
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-12-17 01:17:48 +0000
committerChris McDonough <chrism@agendaless.com>2009-12-17 01:17:48 +0000
commit5babbaf48a71af786d41f59a1f1f7d5272a60a4d (patch)
tree4c3c4264e73410db07baffaebd879b36c4ae5aed /repoze
parent0bf2866211d095a18a5c61d7af644c8e17486e6e (diff)
downloadpyramid-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.
Diffstat (limited to 'repoze')
-rw-r--r--repoze/bfg/chameleon_text.py7
-rw-r--r--repoze/bfg/chameleon_zpt.py9
-rw-r--r--repoze/bfg/decorator.py15
-rw-r--r--repoze/bfg/tests/test_chameleon_text.py7
-rw-r--r--repoze/bfg/tests/test_chameleon_zpt.py7
-rw-r--r--repoze/bfg/tests/test_decorator.py23
6 files changed, 66 insertions, 2 deletions
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