[pypy-svn] r53714 - in pypy/dist/pypy: config config/test rlib translator/goal

arigo at codespeak.net arigo at codespeak.net
Sat Apr 12 12:01:56 CEST 2008


Author: arigo
Date: Sat Apr 12 12:01:56 2008
New Revision: 53714

Modified:
   pypy/dist/pypy/config/config.py
   pypy/dist/pypy/config/pypyoption.py
   pypy/dist/pypy/config/test/test_config.py
   pypy/dist/pypy/config/test/test_pypyoption.py
   pypy/dist/pypy/rlib/libffi.py
   pypy/dist/pypy/translator/goal/translate.py
Log:
* Add a hook allowing code to check if bool options can be enabled.

* Use the hook to check if libffi is installed, for '_rawffi'.

* Use a custom ConfigError instead of ValueError to report bad option
  combinations.

* Add a way to report warnings.


Modified: pypy/dist/pypy/config/config.py
==============================================================================
--- pypy/dist/pypy/config/config.py	(original)
+++ pypy/dist/pypy/config/config.py	Sat Apr 12 12:01:56 2008
@@ -10,6 +10,9 @@
 class NoMatchingOptionFound(AttributeError):
     pass
 
+class ConfigError(Exception):
+    pass
+
 class Config(object):
     _cfgimpl_frozen = False
     
@@ -18,6 +21,7 @@
         self._cfgimpl_value_owners = {}
         self._cfgimpl_parent = parent
         self._cfgimpl_values = {}
+        self._cfgimpl_warnings = []
         self._cfgimpl_build(overrides)
 
     def _cfgimpl_build(self, overrides):
@@ -95,7 +99,7 @@
         if oldvalue != value and oldowner not in ("default", "suggested"):
             if who in ("default", "suggested"):
                 return
-            raise ValueError('cannot override value to %s for option %s' %
+            raise ConfigError('cannot override value to %s for option %s' %
                                 (value, name))
         child.setoption(self, value, who)
         self._cfgimpl_value_owners[name] = who
@@ -128,6 +132,12 @@
             self = self._cfgimpl_parent
         return self
 
+    def add_warning(self, warning):
+        self._cfgimpl_get_toplevel()._cfgimpl_warnings.append(warning)
+
+    def get_warnings(self):
+        return self._cfgimpl_get_toplevel()._cfgimpl_warnings
+
     def _freeze_(self):
         self.__dict__['_cfgimpl_frozen'] = True
         return True
@@ -197,7 +207,7 @@
         if who == "default" and value is None:
             pass
         elif not self.validate(value):
-            raise ValueError('invalid value %s for option %s' % (value, name))
+            raise ConfigError('invalid value %s for option %s' % (value, name))
         config._cfgimpl_values[name] = value
 
     def getkey(self, value):
@@ -240,7 +250,7 @@
             homeconfig, name = toplevel._cfgimpl_get_home_by_path(path)
             try:
                 homeconfig.setoption(name, reqvalue, "suggested")
-            except ValueError:
+            except ConfigError:
                 # setting didn't work, but that is fine, since it is
                 # suggested only
                 pass
@@ -262,19 +272,23 @@
 
 class BoolOption(Option):
     def __init__(self, name, doc, default=None, requires=None,
-                 suggests=None,
+                 suggests=None, validator=None,
                  cmdline=DEFAULT_OPTION_NAME, negation=True):
         super(BoolOption, self).__init__(name, doc, cmdline=cmdline)
         self._requires = requires
         self._suggests = suggests
         self.default = default
         self.negation = negation
+        self._validator = validator
 
     def validate(self, value):
         return isinstance(value, bool)
 
     def setoption(self, config, value, who):
         name = self._name
+        if value and self._validator is not None:
+            toplevel = config._cfgimpl_get_toplevel()
+            self._validator(toplevel)
         if value and self._requires is not None:
             for path, reqvalue in self._requires:
                 toplevel = config._cfgimpl_get_toplevel()
@@ -286,7 +300,7 @@
                 homeconfig, name = toplevel._cfgimpl_get_home_by_path(path)
                 try:
                     homeconfig.setoption(name, reqvalue, "suggested")
-                except ValueError:
+                except ConfigError:
                     # setting didn't work, but that is fine, since it is
                     # suggested
                     pass
@@ -330,7 +344,7 @@
         try:
             super(IntOption, self).setoption(config, int(value), who)
         except TypeError, e:
-            raise ValueError(*e.args)
+            raise ConfigError(*e.args)
 
 
 class FloatOption(Option):
@@ -351,7 +365,7 @@
         try:
             super(FloatOption, self).setoption(config, float(value), who)
         except TypeError, e:
-            raise ValueError(*e.args)
+            raise ConfigError(*e.args)
 
 
 class StrOption(Option):
@@ -368,7 +382,7 @@
         try:
             super(StrOption, self).setoption(config, value, who)
         except TypeError, e:
-            raise ValueError(*e.args)
+            raise ConfigError(*e.args)
 
 
 class ArbitraryOption(Option):
@@ -505,7 +519,7 @@
         try:
             value = self.convert_from_cmdline(value)
             self.config.setoption(self.option._name, value, who='cmdline')
-        except ValueError, e:
+        except ConfigError, e:
             raise optparse.OptionValueError(e.args[0])
 
     def help_default(self):

Modified: pypy/dist/pypy/config/pypyoption.py
==============================================================================
--- pypy/dist/pypy/config/pypyoption.py	(original)
+++ pypy/dist/pypy/config/pypyoption.py	Sat Apr 12 12:01:56 2008
@@ -3,6 +3,7 @@
 import sys
 from pypy.config.config import OptionDescription, BoolOption, IntOption, ArbitraryOption
 from pypy.config.config import ChoiceOption, StrOption, to_optparse, Config
+from pypy.config.config import ConfigError
 
 modulepath = py.magic.autopath().dirpath().dirpath().join("module")
 all_modules = [p.basename for p in modulepath.listdir()
@@ -44,6 +45,29 @@
 if os.name == "posix":
     module_dependencies['rctime'] = [("objspace.usemodules.select", True),]
 
+module_import_dependencies = {
+    # no _rawffi if importing pypy.rlib.libffi raises ImportError
+    "_rawffi": ["pypy.rlib.libffi"],
+    }
+
+def get_module_validator(modname):
+    if modname in module_import_dependencies:
+        modlist = module_import_dependencies[modname]
+        def validator(config):
+            try:
+                for name in modlist:
+                    __import__(name)
+            except ImportError, e:
+                err = "%s: %s" % (e.__class__.__name__, e)
+                config.add_warning(
+                    "The module %r is disabled\n" % (modname,) +
+                    "because importing %s raised\n" % (name,) +
+                    err)
+                raise ConfigError("--withmod-%s: %s" % (modname, err))
+        return validator
+    else:
+        return None
+
 
 pypy_optiondescription = OptionDescription("objspace", "Object Space Options", [
     ChoiceOption("name", "Object Space name",
@@ -89,7 +113,8 @@
                    cmdline="--withmod-%s" % (modname, ),
                    requires=module_dependencies.get(modname, []),
                    suggests=module_suggests.get(modname, []),
-                   negation=modname not in essential_modules)
+                   negation=modname not in essential_modules,
+                   validator=get_module_validator(modname))
         for modname in all_modules]),
 
     BoolOption("allworkingmodules", "use as many working modules as possible",

Modified: pypy/dist/pypy/config/test/test_config.py
==============================================================================
--- pypy/dist/pypy/config/test/test_config.py	(original)
+++ pypy/dist/pypy/config/test/test_config.py	Sat Apr 12 12:01:56 2008
@@ -50,17 +50,17 @@
     config.str = "def"
     assert config.str == "def"
 
-    py.test.raises(ValueError, 'config.objspace = "foo"')
-    py.test.raises(ValueError, 'config.gc.name = "foo"')
+    py.test.raises(ConfigError, 'config.objspace = "foo"')
+    py.test.raises(ConfigError, 'config.gc.name = "foo"')
     py.test.raises(AttributeError, 'config.gc.foo = "bar"')
-    py.test.raises(ValueError, 'config.bool = 123')
-    py.test.raises(ValueError, 'config.int = "hello"')
-    py.test.raises(ValueError, 'config.gc.float = None')
+    py.test.raises(ConfigError, 'config.bool = 123')
+    py.test.raises(ConfigError, 'config.int = "hello"')
+    py.test.raises(ConfigError, 'config.gc.float = None')
 
     config = Config(descr, bool=False)
     assert config.gc.name == 'ref'
     config.wantframework = True
-    py.test.raises(ValueError, 'config.gc.name = "ref"')
+    py.test.raises(ConfigError, 'config.gc.name = "ref"')
     config.gc.name = "framework"
 
 def test_arbitrary_option():
@@ -439,7 +439,7 @@
     assert not c2.s1.a
     c2.s1.a = True
     assert c2.s1.a
-    py.test.raises(ValueError, "c2.int = 44")
+    py.test.raises(ConfigError, "c2.int = 44")
     c2 = c1.copy(as_default=True)
     assert c2.int == 43
     assert not c2.s1.a
@@ -542,3 +542,32 @@
     assert c.int == 42
     c.int = 45
     assert c.int == 45
+
+def test_validator():
+    def my_validator_1(config):
+        assert config is c
+
+    def my_validator_2(config):
+        assert config is c
+        raise ConfigError
+
+    descr = OptionDescription("opt", "", [
+        BoolOption('booloption1', 'option test1', default=False,
+                   validator=my_validator_1),
+        BoolOption('booloption2', 'option test2', default=False,
+                   validator=my_validator_2),
+        BoolOption('booloption3', 'option test3', default=False,
+                   requires=[("booloption2", True)]),
+        BoolOption('booloption4', 'option test4', default=False,
+                   suggests=[("booloption2", True)]),
+        ])
+    c = Config(descr)
+    c.booloption1 = True
+    py.test.raises(ConfigError, "c.booloption2 = True")
+    assert c.booloption2 is False
+    py.test.raises(ConfigError, "c.booloption3 = True")
+    assert c.booloption2 is False
+    c.booloption4 = True
+    assert c.booloption2 is False
+    c.booloption2 = False
+    assert c.booloption2 is False

Modified: pypy/dist/pypy/config/test/test_pypyoption.py
==============================================================================
--- pypy/dist/pypy/config/test/test_pypyoption.py	(original)
+++ pypy/dist/pypy/config/test/test_pypyoption.py	Sat Apr 12 12:01:56 2008
@@ -1,6 +1,6 @@
 import py
 from pypy.config.pypyoption import get_pypy_config
-from pypy.config.config import Config
+from pypy.config.config import Config, ConfigError
 
 thisdir = py.magic.autopath().dirpath()
 
@@ -14,7 +14,7 @@
     assert not conf.objspace.std.withprebuiltint
     conf = get_pypy_config()
     conf.objspace.std.withprebuiltint = True
-    py.test.raises(ValueError, "conf.objspace.std.withsmallint = True")
+    py.test.raises(ConfigError, "conf.objspace.std.withsmallint = True")
 
 def test_stacklessgc_required():
     conf = get_pypy_config()
@@ -25,7 +25,7 @@
     assert conf.translation.gc == "generation"
     conf = get_pypy_config()
     conf.translation.gc = "boehm"
-    py.test.raises(ValueError, "conf.translation.gcrootfinder = 'stackless'")
+    py.test.raises(ConfigError, "conf.translation.gcrootfinder = 'stackless'")
 
 
 def test_frameworkgc():

Modified: pypy/dist/pypy/rlib/libffi.py
==============================================================================
--- pypy/dist/pypy/rlib/libffi.py	(original)
+++ pypy/dist/pypy/rlib/libffi.py	Sat Apr 12 12:01:56 2008
@@ -51,6 +51,9 @@
 
     ffi_closure = rffi_platform.Struct('ffi_closure', [])
 
+if not rffi_platform.check_eci(CConfig._compilation_info_):
+    raise ImportError("cannot find an installed 'libffi' library")
+
 def add_simple_type(type_name):
     for name in ['size', 'alignment', 'type']:
         setattr(CConfig, type_name + '_' + name,

Modified: pypy/dist/pypy/translator/goal/translate.py
==============================================================================
--- pypy/dist/pypy/translator/goal/translate.py	(original)
+++ pypy/dist/pypy/translator/goal/translate.py	Sat Apr 12 12:01:56 2008
@@ -193,6 +193,8 @@
 def log_config(config, header="config used"):
     log('%s:' % header)
     log(str(config))
+    for warning in config.get_warnings():
+        log.WARNING(warning)
 
 def main():
     targetspec_dic, translateconfig, config, args = parse_options_and_load_target()



More information about the Pypy-commit mailing list