[Repoze-checkins] r1625 - in repoze.bfg/trunk: . docs/narr docs/narr/myproject/myproject repoze/bfg repoze/bfg/sampleapp repoze/bfg/tests

Chris McDonough chrism at agendaless.com
Sun Aug 17 13:32:54 EDT 2008


Author: Chris McDonough <chrism at agendaless.com>
Date: Sun Aug 17 13:32:54 2008
New Revision: 1625

Log:
  - Add ``<bfg:settings>`` directive.  This directive currently allows
    only one attribute: ``reload_templates``.  If e.g.::

         <bfg:settings reload_templates="true"/>

    is in your application's ZCML, you will not need to restart the
    appserver in order for ``z3c.pt`` or XSLT template changes to be
    detected and displayed.



Modified:
   repoze.bfg/trunk/CHANGES.txt
   repoze.bfg/trunk/docs/narr/myproject/myproject/configure.zcml
   repoze.bfg/trunk/docs/narr/project.rst
   repoze.bfg/trunk/repoze/bfg/interfaces.py
   repoze.bfg/trunk/repoze/bfg/meta.zcml
   repoze.bfg/trunk/repoze/bfg/sampleapp/configure.zcml
   repoze.bfg/trunk/repoze/bfg/template.py
   repoze.bfg/trunk/repoze/bfg/tests/test_zcml.py
   repoze.bfg/trunk/repoze/bfg/zcml.py

Modified: repoze.bfg/trunk/CHANGES.txt
==============================================================================
--- repoze.bfg/trunk/CHANGES.txt	(original)
+++ repoze.bfg/trunk/CHANGES.txt	Sun Aug 17 13:32:54 2008
@@ -1,3 +1,14 @@
+Next release
+
+  - Add ``<bfg:settings>`` directive.  This directive currently allows
+    only one attribute: ``reload_templates``.  If e.g.::
+
+         <bfg:settings reload_templates="true"/>
+
+    is in your application's ZCML, you will not need to restart the
+    appserver in order for ``z3c.pt`` or XSLT template changes to be
+    detected and displayed.
+
 0.3.0
 
   - Add ``get_template`` API to template module.

Modified: repoze.bfg/trunk/docs/narr/myproject/myproject/configure.zcml
==============================================================================
--- repoze.bfg/trunk/docs/narr/myproject/myproject/configure.zcml	(original)
+++ repoze.bfg/trunk/docs/narr/myproject/myproject/configure.zcml	Sun Aug 17 13:32:54 2008
@@ -2,9 +2,13 @@
 	   xmlns:bfg="http://namespaces.repoze.org/bfg"
 	   i18n_domain="repoze.bfg">
 
-  <!-- this must be included for the view declarations to work -->
+  <!-- this directive must be included for the view declarations to work -->
   <include package="repoze.bfg" />
 
+  <!-- this directive indicates that changes to templates should show up
+       immediately -->
+  <bfg:settings reload_templates="true"/>
+
   <bfg:view
      for=".models.IMyModel"
      view=".views.my_view"

Modified: repoze.bfg/trunk/docs/narr/project.rst
==============================================================================
--- repoze.bfg/trunk/docs/narr/project.rst	(original)
+++ repoze.bfg/trunk/docs/narr/project.rst	Sun Aug 17 13:32:54 2008
@@ -416,7 +416,10 @@
 #. Line 6 initializes :mod:`repoze.bfg`-specific configuration
    directives by including it as a package.
 
-#. Lines 8-11 register a single view.  It is ``for`` model objects
+#. Line 10 tells :mod:`repoze.bfg` to detect changes made to
+ ``z3c.pt`` and XSLT templates immediately.
+
+#. Lines 12-15 register a single view.  It is ``for`` model objects
    that support the IMyModel interface.  The ``view`` attribute points
    at a Python function that does all the work for this view.  Note
    that the values of both the ``for`` attribute and the ``view``
@@ -451,7 +454,16 @@
    ``Request`` class representing the browser's request to our server.
 
 #. The view renders a :term:`template` and returns the result as the
-   :term:`response`.
+   :term:`response`.  Note that because our ``configure.zcml`` has a
+   ``bfg:settings`` directive indicating that templates should be
+   reloaded when they change, you won't need to restart the
+   application server to see changes you make to templates.  During
+   development, this is handy.  If this directive had been ``false``
+   (or if the directive did not exist), you would need to restart the
+   application server for each template change.  For production
+   applications, you should set your ``bfg:settings``
+   ``reload_templates`` to ``false`` to increase the speed at which
+   templates may be rendered.
 
 .. note::
 
@@ -460,7 +472,9 @@
   the ``render_template`` function, also present in
   :ref:`template_module`.  You may then create your own :term:`WebOb`
   Response object, using the result of ``render_template`` as the
-  response's body.
+  response's body.  There is also a ``get_template`` API in the same
+  module, which you can use to retrieve the template object without
+  rendering it at all, for additional control.
 
 ``models.py``
 ~~~~~~~~~~~~~

Modified: repoze.bfg/trunk/repoze/bfg/interfaces.py
==============================================================================
--- repoze.bfg/trunk/repoze/bfg/interfaces.py	(original)
+++ repoze.bfg/trunk/repoze/bfg/interfaces.py	Sun Aug 17 13:32:54 2008
@@ -27,7 +27,7 @@
         """ Return an object that implements IPublishTraverser """
 
 class ITemplateFactory(Interface):
-    def __call__(path):
+    def __call__(path, auto_reload=False):
         """ Return an an ITemplate given a filesystem path """
 
 class ITemplate(Interface):
@@ -79,3 +79,8 @@
     """ An event type that is emitted whenever any repoze.bfg view
     returns a response."""
     response = Attribute('The response object')
+
+class ISettings(Interface):
+    """ Runtime settings for repoze.bfg """
+    reload_templates = Attribute('Reload templates when they change')
+    

Modified: repoze.bfg/trunk/repoze/bfg/meta.zcml
==============================================================================
--- repoze.bfg/trunk/repoze/bfg/meta.zcml	(original)
+++ repoze.bfg/trunk/repoze/bfg/meta.zcml	Sun Aug 17 13:32:54 2008
@@ -10,6 +10,12 @@
         handler=".zcml.view"
         />
 
+    <meta:directive
+        name="settings"
+        schema=".zcml.ISettingsDirective"
+        handler=".zcml.settings"
+        />
+
   </meta:directives>
 
 </configure>

Modified: repoze.bfg/trunk/repoze/bfg/sampleapp/configure.zcml
==============================================================================
--- repoze.bfg/trunk/repoze/bfg/sampleapp/configure.zcml	(original)
+++ repoze.bfg/trunk/repoze/bfg/sampleapp/configure.zcml	Sun Aug 17 13:32:54 2008
@@ -4,6 +4,9 @@
 
   <include package="repoze.bfg" />
 
+  <bfg:settings
+       reload_templates="true"/>
+
   <utility
     provides="repoze.bfg.interfaces.ISecurityPolicy"
     factory="repoze.bfg.security.RemoteUserACLSecurityPolicy"

Modified: repoze.bfg/trunk/repoze/bfg/template.py
==============================================================================
--- repoze.bfg/trunk/repoze/bfg/template.py	(original)
+++ repoze.bfg/trunk/repoze/bfg/template.py	Sun Aug 17 13:32:54 2008
@@ -13,14 +13,19 @@
 from repoze.bfg.interfaces import ITemplateFactory
 from repoze.bfg.interfaces import ITemplate
 from repoze.bfg.interfaces import INodeTemplate
+from repoze.bfg.interfaces import ISettings
 
 class Z3CPTTemplateFactory(object):
     classProvides(ITemplateFactory)
     implements(ITemplate)
 
-    def __init__(self, path):
+    def __init__(self, path, auto_reload=False):
         from z3c.pt import PageTemplateFile
-        self.template = PageTemplateFile(path)
+        try:
+            self.template = PageTemplateFile(path, auto_reload=auto_reload)
+        except TypeError:
+            # z3c.pt before 1.0
+            self.template = PageTemplateFile(path)
 
     def __call__(self, **kw):
         result = self.template.render(**kw)
@@ -30,11 +35,12 @@
     classProvides(ITemplateFactory)
     implements(INodeTemplate)
 
-    def __init__(self, path):
+    def __init__(self, path, auto_reload=False):
         self.path = path
+        self.auto_reload = auto_reload
 
     def __call__(self, node, **kw):
-        processor = get_processor(self.path)
+        processor = get_processor(self.path, self.auto_reload)
         result = str(processor(node, **kw))
         return result
 
@@ -42,13 +48,14 @@
 import threading
 from lxml import etree
 xslt_pool = threading.local()
-def get_processor(xslt_fn):
-    try:
-        return xslt_pool.processors[xslt_fn]
-    except AttributeError:
-        xslt_pool.processors = {}
-    except KeyError:
-        pass
+def get_processor(xslt_fn, auto_reload=False):
+    if not auto_reload:
+        try:
+            return xslt_pool.processors[xslt_fn]
+        except AttributeError:
+            xslt_pool.processors = {}
+        except KeyError:
+            pass
 
     # Make a processor and add it to the pool
     source = etree.ElementTree(file=xslt_fn)
@@ -74,7 +81,9 @@
     if template is None:
         if not os.path.exists(path):
             raise ValueError('Missing template file: %s' % path)
-        template = Z3CPTTemplateFactory(path)
+        settings = queryUtility(ISettings)
+        auto_reload = settings and settings.reload_templates
+        template = Z3CPTTemplateFactory(path, auto_reload)
         registerTemplate(ITemplate, template, path)
 
     return template

Modified: repoze.bfg/trunk/repoze/bfg/tests/test_zcml.py
==============================================================================
--- repoze.bfg/trunk/repoze/bfg/tests/test_zcml.py	(original)
+++ repoze.bfg/trunk/repoze/bfg/tests/test_zcml.py	Sun Aug 17 13:32:54 2008
@@ -114,6 +114,37 @@
         self.assertEqual(regadapt['args'][4], '')
         self.assertEqual(regadapt['args'][5], None)
 
+class TestSettingsDirective(unittest.TestCase, PlacelessSetup):
+    def setUp(self):
+        PlacelessSetup.setUp(self)
+
+    def tearDown(self):
+        PlacelessSetup.tearDown(self)
+
+    def _getFUT(self):
+        from repoze.bfg.zcml import settings
+        return settings
+
+    def test_defaults(self):
+        context = DummyContext()
+        settings = self._getFUT()
+        settings(context)
+        actions = context.actions
+        from repoze.bfg.interfaces import ISettings
+        from zope.component.zcml import handler
+        self.assertEqual(len(actions), 1)
+        action = actions[0]
+        self.assertEqual(action['discriminator'], ('settings', ISettings))
+        self.assertEqual(action['callable'], handler)
+        self.assertEqual(len(action['args']), 5)
+        self.assertEqual(action['args'][0], 'registerUtility')
+        settings = action['args'][1]
+        self.assertEqual(settings.reload_templates, False)
+        self.failUnless(ISettings.providedBy(settings), settings)
+        self.assertEqual(action['args'][2], ISettings)
+        self.assertEqual(action['args'][3], '')
+        self.assertEqual(action['args'][4], context.info)
+
 class TestSampleApp(unittest.TestCase, PlacelessSetup):
     def setUp(self):
         PlacelessSetup.setUp(self)

Modified: repoze.bfg/trunk/repoze/bfg/zcml.py
==============================================================================
--- repoze.bfg/trunk/repoze/bfg/zcml.py	(original)
+++ repoze.bfg/trunk/repoze/bfg/zcml.py	Sun Aug 17 13:32:54 2008
@@ -2,17 +2,44 @@
 from zope.component.interface import provideInterface
 from zope.configuration.exceptions import ConfigurationError
 from zope.configuration.fields import GlobalObject
+from zope.configuration.fields import Bool
 
 from zope.interface import Interface
+from zope.interface import implements
 
 from zope.schema import TextLine
 
 from repoze.bfg.interfaces import IRequest
 from repoze.bfg.interfaces import IViewPermission
 from repoze.bfg.interfaces import IView
+from repoze.bfg.interfaces import ISettings
 
 from repoze.bfg.security import ViewPermissionFactory
 
+def _handler(*arg, **kw):
+    import pdb; pdb.set_trace()
+    return handler(*arg, **kw)
+
+class Settings(object):
+    implements(ISettings)
+    def __init__(self, reload_templates=False):
+        self.reload_templates = reload_templates
+
+def settings(_context, reload_templates=False):
+    settings = Settings(reload_templates=reload_templates)
+    _context.action(
+        discriminator = ('settings', ISettings),
+        callable = handler,
+        args = ('registerUtility', settings, ISettings, '', _context.info),
+        )
+
+class ISettingsDirective(Interface):
+    reload_templates = Bool(
+        title=u"Reload templates when they change",
+        description=(u"Specifies whether templates should be reloaded when"
+                     "a change is made"),
+        default=False)
+
 def view(_context,
          permission=None,
          for_=None,


More information about the Repoze-checkins mailing list