[Piglit] [PATCH v2 04/16] framework/core.py: Add a custom PiglitConfig class

Dylan Baker baker.dylan.c at gmail.com
Mon May 18 10:57:38 PDT 2015


This allows us to encapsulate a lot of the error handling logic into a
single place with easy to use methods. This should reduce the amount of
code in consumers of PIGLIT_CONFIG.

It adds two new methods, safe_get and required_get, which operate on
NoOptionError or NoSectionError. With safe_get, if either of these is
raised None will be return, for required_get a PiglitFatalError will be
raised.

Signed-off-by: Dylan Baker <dylanx.c.baker at intel.com>
---
 framework/core.py             | 56 +++++++++++++++++++++++++++++--
 framework/tests/core_tests.py | 76 ++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 122 insertions(+), 10 deletions(-)

diff --git a/framework/core.py b/framework/core.py
index 3ee2870..f9cdbfe 100644
--- a/framework/core.py
+++ b/framework/core.py
@@ -30,17 +30,69 @@ import subprocess
 import sys
 import ConfigParser
 
+from framework import exceptions
+
 __all__ = [
     'PIGLIT_CONFIG',
     'PLATFORMS',
+    'PiglitConfig',
     'Options',
     'collect_system_info',
     'parse_listfile',
 ]
 
-
 PLATFORMS = ["glx", "x11_egl", "wayland", "gbm", "mixed_glx_egl"]
-PIGLIT_CONFIG = ConfigParser.SafeConfigParser(allow_no_value=True)
+
+
+class PiglitConfig(ConfigParser.SafeConfigParser):
+    """Custom Config parser that provides a few extra helpers."""
+    def __init__(self, *args, **kwargs):
+        # In Python2 the ConfigParser classes are old style, you can't use
+        # super() on them. sigh
+        ConfigParser.SafeConfigParser.__init__(self, *args, **kwargs)
+        self.filename = None
+
+    def readfp(self, fp, filename=None):
+        # In Python2 the ConfigParser classes are old style, you can't use
+        # super() on them. sigh
+        ConfigParser.SafeConfigParser.readfp(self, fp, filename)
+        self.filename = os.path.abspath(filename or fp.name)
+
+    def safe_get(self, *args, **kwargs):
+        """A version of self.get that doesn't raise NoSectionError or
+        NoOptionError.
+
+        This is equivalent to passing if the option isn't found. It will return
+        None if an error is caught
+
+        """
+        try:
+            return self.get(*args, **kwargs)
+        except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
+            return None
+
+    def required_get(self, section, option, **kwargs):
+        """A version fo self.get that raises PiglitFatalError.
+
+        If self.get returns NoSectionError or NoOptionError then this will
+        raise a PiglitFatalException, aborting the program.
+
+        """
+        try:
+            return self.get(section, option, **kwargs)
+        except ConfigParser.NoSectionError:
+            raise exceptions.PiglitFatalError(
+                'No Section "{}" in file "{}".\n'
+                'This section is required.'.format(
+                    section, self.filename))
+        except ConfigParser.NoOptionError:
+            raise exceptions.PiglitFatalError(
+                'No option "{}"  from section "{}" in file "{}".\n'
+                'This option is required.'.format(
+                    option, section, self.filename))
+
+
+PIGLIT_CONFIG = PiglitConfig(allow_no_value=True)
 
 
 def get_config(arg=None):
diff --git a/framework/tests/core_tests.py b/framework/tests/core_tests.py
index d3ca563..9a49515 100644
--- a/framework/tests/core_tests.py
+++ b/framework/tests/core_tests.py
@@ -24,14 +24,16 @@ from __future__ import print_function, absolute_import
 import os
 import collections
 import shutil
-import ConfigParser
 import textwrap
 import functools
+import ConfigParser
 
 import nose.tools as nt
 
+from framework import core, exceptions
 import framework.tests.utils as utils
-import framework.core as core
+
+# pylint: disable=line-too-long,invalid-name
 
 _CONF_FILE = textwrap.dedent("""\
 [nose-test]
@@ -80,7 +82,7 @@ def _save_core_config(func):
 
             if restore_piglitconf:
                 shutil.move('piglit.conf.restore', 'piglit.conf')
-            core.PIGLIT_CONFIG = ConfigParser.SafeConfigParser(
+            core.PIGLIT_CONFIG = core.PiglitConfig(
                 allow_no_value=True)
         except Exception as e:
             raise utils.UtilsError(e)
@@ -90,13 +92,31 @@ def _save_core_config(func):
 
 def _reset_piglit_config():
     """ Set core.PIGLIT_CONFIG back to pristine """
-    core.PIGLIT_CONFIG = ConfigParser.SafeConfigParser()
+    core.PIGLIT_CONFIG = core.PiglitConfig(allow_no_value=True)
 
 
- at utils.no_error
-def test_options_init():
-    """core.Options(): Class initializes"""
-    core.Options()
+ at utils.nose_generator
+def test_generate_initialize():
+    """ Generator that creates tests to initialize all of the classes in core
+
+    In a compiled language the compiler provides this kind of checking, but in
+    an interpreted language like python you don't have a compiler test. The
+    unit tests generated by this function serve as a similar test, does this
+    even work?
+
+    """
+    def check_initialize(target):
+        """ Check that a class initializes without error """
+        func = target()
+        # Asserting that func exists will fail for Group and TestrunResult which
+        # are dict subclasses
+        assert isinstance(func, target)
+
+
+    for target in [core.Options, core.PiglitConfig]:
+        check_initialize.description = "Test that {} initializes".format(
+            target.__name__)
+        yield check_initialize, target
 
 
 def test_parse_listfile_return():
@@ -213,3 +233,43 @@ def test_piglit_root():
 
     nt.ok_(core.PIGLIT_CONFIG.has_section('nose-test'),
            msg='$PIGLIT_ROOT not found')
+
+
+class TestPiglitConfig(object):
+    """Tests for PiglitConfig methods."""
+    @classmethod
+    def setup_class(cls):
+        cls.conf = core.PiglitConfig()
+        cls.conf.add_section('set')
+        cls.conf.set('set', 'options', 'bool')
+
+    def test_safe_get_valid(self):
+        """core.PiglitConfig: safe_get returns a value if its in the Config"""
+        nt.assert_equal(self.conf.safe_get('set', 'options'), 'bool')
+
+    def test_PiglitConfig_required_get_valid(self):
+        """core.PiglitConfig: required_get returns a value if its in the Config
+        """
+        nt.assert_equal(self.conf.required_get('set', 'options'), 'bool')
+
+    def test_safe_get_missing_option(self):
+        """core.PiglitConfig: safe_get returns None if the option is missing
+        """
+        nt.assert_equal(self.conf.safe_get('set', 'invalid'), None)
+
+    def test_safe_get_missing_section(self):
+        """core.PiglitConfig: safe_get returns None if the section is missing
+        """
+        nt.assert_equal(self.conf.safe_get('invalid', 'invalid'), None)
+
+    @nt.raises(exceptions.PiglitFatalError)
+    def test_required_get_missing_option(self):
+        """core.PiglitConfig: required_get raises PiglitFatalError if the option is missing
+        """
+        self.conf.required_get('set', 'invalid')
+
+    @nt.raises(exceptions.PiglitFatalError)
+    def test_required_get_missing_section(self):
+        """core.PiglitConfig: required_get raises PiglitFatalError if the section is missing
+        """
+        self.conf.required_get('invalid', 'invalid')
-- 
2.4.0



More information about the Piglit mailing list