Validation error reporting functionality.
authorChristopher Allan Webber <cwebber@dustycloud.org>
Sat, 18 Jun 2011 20:01:32 +0000 (15:01 -0500)
committerChristopher Allan Webber <cwebber@dustycloud.org>
Sat, 18 Jun 2011 20:01:32 +0000 (15:01 -0500)
Changed a few things so we can report errors to users properly in the
config loading system.

 - We now return from read_mediagoblin_config both a loaded config and
   the validation results
 - We now have a helper function generate_validation_report that can
   generate a proper validation report saying if there are errors in a
   way that's useful to users.
 - Moved conf->config in the read_mediagoblin_config function, which
   looks nicer IMO.

mediagoblin/config.py

index 533dbe193dd5cb28fcf49bad714109ba4284497a..2e457e44ca49718e5700a8c589e2c13d1d835246 100644 (file)
@@ -17,7 +17,7 @@
 import os
 import pkg_resources
 
-from configobj import ConfigObj
+from configobj import ConfigObj, flatten_errors
 from validate import Validator
 
 
@@ -42,13 +42,18 @@ def read_mediagoblin_config(config_path, config_spec=CONFIG_SPEC_PATH):
     Also provides %(__file__)s and %(here)s values of this file and
     its directory respectively similar to paste deploy.
 
+    This function doesn't itself raise any exceptions if validation
+    fails, you'll have to do something
+
     Args:
      - config_path: path to the config file
      - config_spec: config file that provides defaults and value types
        for validation / conversion.  Defaults to mediagoblin/config_spec.ini
 
     Returns:
-      A read ConfigObj object.
+      A tuple like: (config, validation_result)
+      ... where 'conf' is the parsed config object and 'validation_result'
+      is the information from the validation process.
     """
     config_path = os.path.abspath(config_path)
 
@@ -58,14 +63,60 @@ def read_mediagoblin_config(config_path, config_spec=CONFIG_SPEC_PATH):
 
     _setup_defaults(config_spec, config_path)
 
-    conf = ConfigObj(
+    config = ConfigObj(
         config_path,
         configspec=config_spec,
         interpolation='ConfigParser')
 
-    _setup_defaults(conf, config_path)
+    _setup_defaults(config, config_path)
+
+    # For now the validator just works with the default functions,
+    # but in the future if we want to add additional validation/configuration
+    # functions we'd add them to validator.functions here.
+    # 
+    # See also:
+    #   http://www.voidspace.org.uk/python/validate.html#adding-functions
+    validator = Validator()
+    validation_result = config.validate(validator, preserve_errors=True)
+
+    return config, validation_result
+
+
+REPORT_HEADER = """\
+There were validation problems loading this config file:
+--------------------------------------------------------
+"""
+
+
+def generate_validation_report(config, validation_result):
+    """
+    Generate a report if necessary of problems while validating.
+
+    Returns:
+      Either a string describing for a user the problems validating
+      this config or None if there are no problems.
+    """
+    report = []
+
+    # Organize the report
+    for entry in flatten_errors(config, validation_result):
+        # each entry is a tuple
+        section_list, key, error = entry
+
+        if key is not None:
+            section_list.append(key)
+        else:
+            section_list.append(u'[missing section]')
+
+        section_string = u':'.join(section_list)
 
-    conf.validate(Validator())
+        if error == False:
+            # We don't care about missing values for now.
+            continue
 
-    return conf
+        report.append(u"%s = %s" % (section_string, error))
 
+    if report:
+        return REPORT_HEADER + u"\n".join(report)
+    else:
+        return None