[Checkins] SVN: z3c.recipe.filetemplate/branches/gary-support-system-python/ revert some of the features; they were annoying to me in practice. Also make error messages better.

Gary Poster gary.poster at canonical.com
Thu Jul 9 23:59:43 EDT 2009


Log message for revision 101784:
  revert some of the features; they were annoying to me in practice.  Also make error messages better.

Changed:
  U   z3c.recipe.filetemplate/branches/gary-support-system-python/CHANGES.txt
  U   z3c.recipe.filetemplate/branches/gary-support-system-python/z3c/recipe/filetemplate/README.txt
  U   z3c.recipe.filetemplate/branches/gary-support-system-python/z3c/recipe/filetemplate/__init__.py
  U   z3c.recipe.filetemplate/branches/gary-support-system-python/z3c/recipe/filetemplate/tests.txt

-=-
Modified: z3c.recipe.filetemplate/branches/gary-support-system-python/CHANGES.txt
===================================================================
--- z3c.recipe.filetemplate/branches/gary-support-system-python/CHANGES.txt	2009-07-10 02:37:32 UTC (rev 101783)
+++ z3c.recipe.filetemplate/branches/gary-support-system-python/CHANGES.txt	2009-07-10 03:59:42 UTC (rev 101784)
@@ -17,12 +17,9 @@
   packages in site-packages causing other dependencies to be masked with the
   versions in site-packages.
 
-- Support escaping "$" with "$$" in templates.  This is particularly useful
-  for *NIX shell scripts.
+- Support escaping "${...}" with "$${...}" in templates.  This is particularly
+  useful for *NIX shell scripts.
 
-- Support specifying local options in templates without braces (e.g.,
-  "Hello $world" is now equivalent to "Hello ${world}".
-
 -----
 Fixes
 -----

Modified: z3c.recipe.filetemplate/branches/gary-support-system-python/z3c/recipe/filetemplate/README.txt
===================================================================
--- z3c.recipe.filetemplate/branches/gary-support-system-python/z3c/recipe/filetemplate/README.txt	2009-07-10 02:37:32 UTC (rev 101783)
+++ z3c.recipe.filetemplate/branches/gary-support-system-python/z3c/recipe/filetemplate/README.txt	2009-07-10 03:59:42 UTC (rev 101784)
@@ -49,13 +49,12 @@
     >>> cat(sample_buildout, 'helloworld.txt')
     Hello Philipp!
 
-If the option name does not have a space or a period in it, you do not need the
-braces in the template.  Notice this example uses "$world" not "${world}" for
-the same result as before.
+If you need to escape the ${...} pattern, you can do so by repeating the dollar
+sign.
 
     >>> write_and_wait(sample_buildout, 'helloworld.txt.in',
     ... """
-    ... Hi $world!
+    ... Hello world! The double $${dollar-sign} escapes!
     ... """)
 
     >>> print system(buildout)
@@ -63,14 +62,13 @@
     Installing message.
 
     >>> cat(sample_buildout, 'helloworld.txt')
-    Hi Philipp!
+    Hello world! The double ${dollar-sign} escapes!
 
-You can escape the dollar sign by repeating it, as with the Python string
-template class.
+Note that dollar signs alone, without curly braces, are not parsed.
 
     >>> write_and_wait(sample_buildout, 'helloworld.txt.in',
     ... """
-    ... Hello $$$world! The double $${dollar-sign} escapes!
+    ... $Hello $$world! $$$profit!
     ... """)
 
     >>> print system(buildout)
@@ -78,7 +76,7 @@
     Installing message.
 
     >>> cat(sample_buildout, 'helloworld.txt')
-    Hello $Philipp! The double ${dollar-sign} escapes!
+    $Hello $$world! $$$profit!
 
 Note that the output file uses the same permission bits as found on the input
 file.

Modified: z3c.recipe.filetemplate/branches/gary-support-system-python/z3c/recipe/filetemplate/__init__.py
===================================================================
--- z3c.recipe.filetemplate/branches/gary-support-system-python/z3c/recipe/filetemplate/__init__.py	2009-07-10 02:37:32 UTC (rev 101783)
+++ z3c.recipe.filetemplate/branches/gary-support-system-python/z3c/recipe/filetemplate/__init__.py	2009-07-10 03:59:42 UTC (rev 101784)
@@ -202,16 +202,18 @@
                 'Destinations already exist: %s. Please make sure that '
                 'you really want to generate these automatically.  Then '
                 'move them away.', ', '.join(already_exists))
-        seen = [] # we throw this away right now, but could move this up
-        # to __init__ if valuable.
+        seen = [] # we throw this away right now, but could move template
+        # processing up to __init__ if valuable.  That would mean that templates
+        # would be rewritten even if a value in another section had been
+        # referenced; however, it would also mean that __init__ would do
+        # virtually all of the work, with install only doing the writing.
         for rel_path, last_mod, st_mode in self.actions:
             source = os.path.join(self.source_dir, rel_path)
             dest = os.path.join(self.destination_dir, rel_path[:-3])
             mode=stat.S_IMODE(st_mode)
-            template=open(source).read()
             # we process the file first so that it won't be created if there
             # is a problem.
-            processed = Template(template).substitute(self, seen)
+            processed = Template(source).substitute(self, seen)
             self._create_paths(os.path.dirname(dest))
             result=open(dest, "wt")
             result.write(processed)
@@ -234,26 +236,22 @@
     # hacked from string.Template
     pattern = re.compile(r"""
     \$(?:
-      (?P<escaped>\$) |                   # Escape sequence of two delimiters.
-      (?P<named>[-a-z0-9_]+) |           # Delimiter and a local option without
-                                         # space or period.
+      \${(?P<escaped>[^}]*)} |                   # Escape sequence of two delimiters.
       {(?P<braced_single>[-a-z0-9 ._]+)} |
                                          # Delimiter and a braced local option
       {(?P<braced_double>[-a-z0-9 ._]+:[-a-z0-9 ._]+)} |
                                          # Delimiter and a braced fully
                                          # qualified option (that is, with
                                          # explicit section).
-      (?P<invalid>)                      # Other ill-formed delimiter exprs.
+      {(?P<invalid>[^}]*})               # Other ill-formed delimiter exprs.
     )
     """, re.IGNORECASE | re.VERBOSE)
 
-    def __init__(self, template):
-        self.template = template
+    def __init__(self, source):
+        self.source = source
+        self.template = open(source).read()
 
-    # Search for $$, $identifier, ${identifier}, and any bare $'s
-
-    def _invalid(self, mo):
-        i = mo.start('invalid')
+    def _get_colno_lineno(self, i):
         lines = self.template[:i].splitlines(True)
         if not lines:
             colno = 1
@@ -261,36 +259,44 @@
         else:
             colno = i - len(''.join(lines[:-1]))
             lineno = len(lines)
-        raise ValueError('Invalid placeholder %r in string: line %d, col %d' %
-                         (mo.group('invalid'), lineno, colno))
+        return colno, lineno
 
-    def _get(self, options, section, option, seen):
+    def _get(self, options, section, option, seen, start):
         value = options.get(option, None, seen)
         if value is None:
+            colno, lineno = self._get_colno_lineno(start)
             raise zc.buildout.buildout.MissingOption(
-                "Referenced option does not exist:", section, option)
+                "Option '%s:%s', referenced in line %d, col %d of %s, "
+                "does not exist." %
+                (section, option, lineno, colno, self.source))
         return value
 
     def substitute(self, recipe, seen):
         # Helper function for .sub()
         def convert(mo):
             # Check the most common path first.
-            local = mo.group('named') or mo.group('braced_single')
-            if local is not None:
-                val = self._get(recipe.options, recipe.name, local, seen)
+            option = mo.group('braced_single')
+            if option is not None:
+                val = self._get(recipe.options, recipe.name, option, seen,
+                                mo.start('braced_single'))
                 # We use this idiom instead of str() because the latter will
                 # fail if val is a Unicode containing non-ASCII characters.
                 return '%s' % (val,)
             double = mo.group('braced_double')
             if double is not None:
                 section, option = double.split(':')
-                val = self._get(
-                    recipe.buildout[section], section, option, seen)
+                val = self._get(recipe.buildout[section], section, option, seen,
+                                mo.start('braced_double'))
                 return '%s' % (val,)
-            if mo.group('escaped') is not None:
-                return '$'
-            if mo.group('invalid') is not None:
-                self._invalid(mo)
+            escaped = mo.group('escaped')
+            if escaped is not None:
+                return '${%s}' % (escaped,)
+            invalid = mo.group('invalid')
+            if invalid is not None:
+                colno, lineno = self._get_colno_lineno(mo.start('invalid'))
+                raise ValueError(
+                    'Invalid placeholder %r in line %d, col %d of %s' %
+                    (mo.group('invalid'), lineno, colno, self.source))
             raise ValueError('Unrecognized named group in pattern',
                              self.pattern) # programmer error, AFAICT
         return self.pattern.sub(convert, self.template)

Modified: z3c.recipe.filetemplate/branches/gary-support-system-python/z3c/recipe/filetemplate/tests.txt
===================================================================
--- z3c.recipe.filetemplate/branches/gary-support-system-python/z3c/recipe/filetemplate/tests.txt	2009-07-10 02:37:32 UTC (rev 101783)
+++ z3c.recipe.filetemplate/branches/gary-support-system-python/z3c/recipe/filetemplate/tests.txt	2009-07-10 03:59:42 UTC (rev 101784)
@@ -148,11 +148,12 @@
     ... files = missing.txt
     ... """)
   
-    >>> print system(buildout)
+    >>> print system(buildout) # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
     Installing missing.
     While:
       Installing missing.
-    Error: Referenced option does not exist: missing world
+    Error: Option 'missing:world', referenced in line 2, col 8 of
+           .../sample-buildout/missing.txt.in, does not exist.
 
 No changes means just an update
 -------------------------------



More information about the Checkins mailing list