[Checkins] SVN: zc.buildout/trunk/ - Improved error handling. No longer show tracebacks for user errors.

Jim Fulton jim at zope.com
Wed Aug 16 17:47:29 EDT 2006


Log message for revision 69574:
  - Improved error handling.  No longer show tracebacks for user errors.
  
  - Now require a recipe option (and therefore a section) for every part.
  

Changed:
  U   zc.buildout/trunk/README.txt
  U   zc.buildout/trunk/src/zc/buildout/buildout.py
  U   zc.buildout/trunk/src/zc/buildout/buildout.txt
  U   zc.buildout/trunk/src/zc/buildout/tests.py

-=-
Modified: zc.buildout/trunk/README.txt
===================================================================
--- zc.buildout/trunk/README.txt	2006-08-16 21:17:19 UTC (rev 69573)
+++ zc.buildout/trunk/README.txt	2006-08-16 21:47:28 UTC (rev 69574)
@@ -189,6 +189,13 @@
 Change History
 ==============
 
+1.0.0b3
+-------
+
+- Improved error handling.  No longer show tracebacks for user errors.
+
+- Now require a recipe option (and therefore a section) for every part.
+
 1.0.0b2
 -------
 

Modified: zc.buildout/trunk/src/zc/buildout/buildout.py
===================================================================
--- zc.buildout/trunk/src/zc/buildout/buildout.py	2006-08-16 21:17:19 UTC (rev 69573)
+++ zc.buildout/trunk/src/zc/buildout/buildout.py	2006-08-16 21:47:28 UTC (rev 69574)
@@ -29,10 +29,21 @@
 import pkg_resources
 import zc.buildout.easy_install
 
-class MissingOption(KeyError):
+class UserError(Exception):
+    """Errors made by a user 
+    """
+
+    def __str__(self):
+        return " ".join(map(str, self))
+
+class MissingOption(UserError, KeyError):
     """A required option was missing
     """
 
+class MissingSection(UserError, KeyError):
+    """A required section is missinh
+    """
+
 class Options(dict):
 
     def __init__(self, buildout, section, data):
@@ -44,7 +55,8 @@
         try:
             return super(Options, self).__getitem__(option)
         except KeyError:
-            raise MissingOption("Missing option", self.section, option)
+            raise MissingOption("Missing option: %s:%s"
+                                % (self.section, option))
 
     # XXX need test
     def __setitem__(self, option, value):
@@ -133,7 +145,12 @@
         if r is not None:
             return r
         if key in seen:
-            raise ValueError('Circular references', seen, key)
+            raise UserError("Circular reference in substitutions.\n"
+                            "We're evaluating %s\nand are referencing: %s.\n"
+                            % (", ".join([":".join(k) for k in seen]),
+                               ":".join(key)
+                               )
+                            )
         seen.append(key)
         value = '$$'.join([self._dosubs_esc(s, data, converted, seen)
                            for s in value.split('$$')
@@ -151,10 +168,12 @@
             if v is None:
                 options = data.get(s[0])
                 if options is None:
-                    raise KeyError("Referenced section does not exist", s[0])
+                    raise MissingSection(
+                        "Referenced section does not exist", s[0])
                 v = options.get(s[1])
                 if v is None:
-                    raise KeyError("Referenced option does not exist", *s)
+                    raise MissingOption("Referenced option does not exist:",
+                                        *s)
                 if '$' in v:
                     v = self._dosubs(s[0], s[1], v, data, converted, seen)
                     options[s[1]] = v
@@ -335,7 +354,8 @@
         for part in parts:
             options = self.get(part)
             if options is None:
-                options = self[part] = {}
+                raise MissingSection("No section was specified for part", part)
+
             recipe, entry = self._recipe(part, options)
             recipes_requirements.append(recipe)
 
@@ -382,7 +402,7 @@
             options['__buildout_signature__'] = ' '.join(sig)
 
     def _recipe(self, part, options):
-        recipe = options.get('recipe', part)
+        recipe = options['recipe']
         if ':' in recipe:
             recipe, entry = recipe.split(':')
         else:
@@ -528,7 +548,7 @@
 
     filename = os.path.join(base, filename)
     if filename in seen:
-        raise ValueError("Recursive file include", seen, filename)
+        raise UserError("Recursive file include", seen, filename)
 
     base = os.path.dirname(filename)
     seen.append(filename)
@@ -592,7 +612,7 @@
     return d1
 
 def _error(*message):
-    sys.stderr.write(' '.join(message) +'\n')
+    sys.stderr.write('Error: ' + ' '.join(message) +'\n')
     sys.exit(1)
 
 def main(args=None):
@@ -612,9 +632,6 @@
                 else:
                     verbosity -= 10
                 op = op[1:]
-            if op == 'd':
-                op = op[1:]
-                import pdb; pdb.set_trace()
                 
             if op[:1] == 'c':
                 op = op[1:]
@@ -641,8 +658,11 @@
     if verbosity:
         options.append(('buildout', 'verbosity', str(verbosity)))
 
-    buildout = Buildout(config_file, options)
-    buildout._setup_logging()
+    try:
+        buildout = Buildout(config_file, options)
+        buildout._setup_logging()
+    except UserError, v:
+        _error(str(v))
 
     if args:
         command = args.pop(0)
@@ -652,9 +672,13 @@
         command = 'install'
 
     try:
-        getattr(buildout, command)(args)
+        try:
+            getattr(buildout, command)(args)
+        except UserError, v:
+            _error(str(v))
+            
     finally:
-        logging.shutdown()
+            logging.shutdown()
 
 if sys.version_info[:2] < (2, 4):
     def reversed(iterable):

Modified: zc.buildout/trunk/src/zc/buildout/buildout.txt
===================================================================
--- zc.buildout/trunk/src/zc/buildout/buildout.txt	2006-08-16 21:17:19 UTC (rev 69573)
+++ zc.buildout/trunk/src/zc/buildout/buildout.txt	2006-08-16 21:47:28 UTC (rev 69574)
@@ -255,8 +255,9 @@
     recipe = recipes:mkdir
     path = mystuff    
 
-Generally, when we name a part, we also create a section of the same
-name that contains part data.  In this section, we'll usually define
+
+When we name a part, we also create a section of the same
+name that contains part data.  In this section, we'll define
 the recipe to be used to install the part.  In this case, we also
 specify the path to be created.
 

Modified: zc.buildout/trunk/src/zc/buildout/tests.py
===================================================================
--- zc.buildout/trunk/src/zc/buildout/tests.py	2006-08-16 21:17:19 UTC (rev 69573)
+++ zc.buildout/trunk/src/zc/buildout/tests.py	2006-08-16 21:47:28 UTC (rev 69574)
@@ -39,7 +39,7 @@
     >>> buildout['buildout']['eek']
     Traceback (most recent call last):
     ...
-    MissingOption: ('Missing option', 'buildout', 'eek')
+    MissingOption: Missing option: buildout:eek
 
 It is an error to create a variable-reference cycle:
 
@@ -55,11 +55,36 @@
 
     >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
     ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
-    Traceback (most recent call last):
+    Error: Circular reference in substitutions.
+    We're evaluating buildout:y, buildout:z, buildout:x
+    and are referencing: buildout:y.
+
+Al parts have to have a section:
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... '''
+    ... [buildout]
+    ... parts = x
+    ... ''')
+
+    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
+    Error: No section was specified for part x
+
+and all parts have to have a specified recipe:
+
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... '''
+    ... [buildout]
+    ... parts = x
     ...
-    ValueError: ('Circular references',
-           [('buildout', 'y'), ('buildout', 'z'), ('buildout', 'x')],
-           ('buildout', 'y'))
+    ... [x]
+    ... foo = 1
+    ... ''')
+
+    >>> print system(os.path.join(sample_buildout, 'bin', 'buildout')),
+    Error: Missing option: x:recipe
+
 """
  
 def test_comparing_saved_options_with_funny_characters():



More information about the Checkins mailing list