[Checkins] SVN: hurry.custom/trunk/ Introduce the notion of a broken template and proper fallback.

Martijn Faassen faassen at startifact.com
Tue Jun 9 10:23:52 EDT 2009


Log message for revision 100760:
  Introduce the notion of a broken template and proper fallback.
  

Changed:
  U   hurry.custom/trunk/CHANGES.txt
  U   hurry.custom/trunk/src/hurry/custom/README.txt
  U   hurry.custom/trunk/src/hurry/custom/core.py
  U   hurry.custom/trunk/src/hurry/custom/interfaces.py

-=-
Modified: hurry.custom/trunk/CHANGES.txt
===================================================================
--- hurry.custom/trunk/CHANGES.txt	2009-06-09 14:21:55 UTC (rev 100759)
+++ hurry.custom/trunk/CHANGES.txt	2009-06-09 14:23:51 UTC (rev 100760)
@@ -4,9 +4,12 @@
 0.6 (unreleased)
 ~~~~~~~~~~~~~~~~
 
-- Nothing changed yet.
+* Introduce the notion of a ``BrokenTemplate``. If a customized
+  template is broken, the system falls back to using the original
+  version of the template. A template is broken if it raises
+  the  ``hurry.custom.interfaces.BrokenTemplate`` exception when it is
+  created.
 
-
 0.5 (2009-05-22)
 ~~~~~~~~~~~~~~~~
 

Modified: hurry.custom/trunk/src/hurry/custom/README.txt
===================================================================
--- hurry.custom/trunk/src/hurry/custom/README.txt	2009-06-09 14:21:55 UTC (rev 100759)
+++ hurry.custom/trunk/src/hurry/custom/README.txt	2009-06-09 14:23:51 UTC (rev 100760)
@@ -60,7 +60,7 @@
 takes the input data (in whatever format is native to the template
 language). The ``ITemplate`` interface defines such an object::
 
-  >>> from hurry.custom.interfaces import ITemplate
+  >>> from hurry.custom.interfaces import ITemplate, BrokenTemplate
 
 For the purposes of demonstrating the functionality in this package,
 we supply a very simplistic push-only templating language, based on
@@ -71,6 +71,8 @@
   >>> class StringTemplate(object):
   ...    implements(ITemplate)
   ...    def __init__(self, text):
+  ...        if '&' in text:
+  ...            raise BrokenTemplate("& in template!")
   ...        self.source = text
   ...        self.template = string.Template(text)
   ...    def __call__(self, input):
@@ -83,6 +85,17 @@
   >>> template({'thing': 'world'})
   'Hello world'
 
+Note we have put some special logic in the ``__init__`` that triggers a
+``BrokenTemplate`` error if the string ``&`` is found in the
+template. This is so we can easily demonstrate templates that are
+broken - treat a template with ``&`` as a template with a syntax
+(compilation) error. Let's try it::
+
+  >>> template = StringTemplate('Hello & bye')
+  Traceback (most recent call last):
+    ...
+  BrokenTemplate: & in template!
+
 The template class defines a template language. Let's register the
 template language so the system is aware of it and treats ``.st`` files
 on the filesystem as a string template::
@@ -111,6 +124,13 @@
   >>> f.write('Hello $thing')
   >>> f.close()
 
+We also create an extra template::
+
+  >>> test2_path = os.path.join(templates_path, 'test2.st')
+  >>> f = open(test2_path, 'w')
+  >>> f.write("It's full of $thing")
+  >>> f.close()
+
 In order for the system to work, we need to register this collection
 of templates on the filesystem. We need to supply a globally unique
 collection id, the templates path, and (optionally) a title::
@@ -133,6 +153,11 @@
   >>> template({'thing': 'world'})
   u'Hello world'
 
+We'll try another template::
+
+  >>> custom.lookup('templates', 'test2.st')({'thing': 'stars'})
+  u"It's full of stars"
+
 The underlying template will not be reloaded unless it is changed on
 the filesystem::
 
@@ -255,6 +280,25 @@
 This could be used to implement a "revert" functionality in a
 customization UI, for instance.
 
+Broken custom template
+----------------------
+
+If a custom template is broken, the system falls back on the
+filesystem template instead. We construct a broken custom template by
+adding ``&`` to it::
+
+  >>> template2 = custom.lookup('templates', 'test2.st')
+  >>> source = template2.source
+  >>> source = source.replace('full of', 'filled with &')
+  >>> mem_db.update('test2.st', source)
+
+We try to render this template, but instead we'll see the original
+template::
+
+  >>> template2 = custom.lookup('templates', 'test2.st')
+  >>> template2({'thing': 'planets'})
+  u"It's full of planets"
+
 Checking which template languages are recognized
 ------------------------------------------------
 
@@ -292,7 +336,11 @@
   [{'extension': '.st',
     'name': 'test1',
     'path': 'test1.st',
-    'template': 'test1.st'}]
+    'template': 'test1.st'},
+   {'extension': '.st',
+    'name': 'test2',
+    'path': 'test2.st',
+    'template': 'test2.st'}]
 
 Samples
 -------

Modified: hurry.custom/trunk/src/hurry/custom/core.py
===================================================================
--- hurry.custom/trunk/src/hurry/custom/core.py	2009-06-09 14:21:55 UTC (rev 100759)
+++ hurry.custom/trunk/src/hurry/custom/core.py	2009-06-09 14:23:51 UTC (rev 100760)
@@ -5,7 +5,7 @@
 from hurry.custom.interfaces import NotSupported
 from hurry.custom.interfaces import (
     ITemplate, IManagedTemplate, ITemplateDatabase, IDataLanguage,
-    ISampleExtension)
+    ISampleExtension, BrokenTemplate)
 
 def register_language(template_class, extension, sample_extension=None):
     component.provideUtility(template_class,
@@ -34,12 +34,19 @@
 
 def lookup(id, template_path):
     db = component.getUtility(ITemplateDatabase, name=id)
-    while db.get_source(template_path) is None:
-        db = getNextUtility(db, ITemplateDatabase, name=id) 
-    dummy, ext = os.path.splitext(template_path)
-    template_class = component.getUtility(ITemplate, name=ext)
-    return ManagedTemplate(template_class, db, template_path)
-
+    while True:
+        source = db.get_source(template_path)
+        if source is None:
+            db = getNextUtility(db, ITemplateDatabase, name=id)
+            continue
+        dummy, ext = os.path.splitext(template_path)
+        template_class = component.getUtility(ITemplate, name=ext)
+        try:
+            return ManagedTemplate(template_class, db, template_path)
+        except BrokenTemplate:
+            db = getNextUtility(db, ITemplateDatabase, name=id)
+            continue
+        
 def sample_datas(id, template_path):
     db = get_filesystem_database(id)
 
@@ -88,7 +95,7 @@
     def samples(self):
         db = _get_root_database(self.db.id)
         return db.get_samples(self.template_path)
-        
+    
 class FilesystemTemplateDatabase(object):
     implements(ITemplateDatabase)
 

Modified: hurry.custom/trunk/src/hurry/custom/interfaces.py
===================================================================
--- hurry.custom/trunk/src/hurry/custom/interfaces.py	2009-06-09 14:21:55 UTC (rev 100759)
+++ hurry.custom/trunk/src/hurry/custom/interfaces.py	2009-06-09 14:23:51 UTC (rev 100760)
@@ -76,7 +76,11 @@
 
         input - opaque template-language native data structure.
         """
-        
+
+class BrokenTemplate(Exception):
+    """Error when a template is broken.
+    """
+    
 class IDataLanguage(Interface):
     def __call__(data):
         """Parse data into data structure that can be passed to ITemplate()"""
@@ -128,6 +132,16 @@
         raised.
         """
 
+    def test(template_id, source):
+        """Test a template.
+
+        This tries a test-compile of the template, and if sample
+        inputs are known, test-renders of the template.
+
+        Return False if the compilation or any of the test renderings
+        fails. Returns True if there was no error.
+        """
+
     def get_source(template_id):
         """Get the source of a given template.
 
@@ -151,4 +165,3 @@
         keys are the unique ids for the sample inputs.
         values are the actual template-language native data structures.
         """
-



More information about the Checkins mailing list