changeset 39046:27fd4beae98e

config: aggregate all options
author Dmitry Selyutin <ghostmansd@gmail.com>
date Fri, 20 Oct 2017 20:24:17 +0300
parents d81a9596b6d7
children 8bd0b74f5c0f
files pygnulib.py pygnulib/config.py pygnulib/module.py
diffstat 3 files changed, 91 insertions(+), 85 deletions(-) [+]
line wrap: on
line diff
--- a/pygnulib.py	Fri Oct 20 17:06:07 2017 +0300
+++ b/pygnulib.py	Fri Oct 20 20:24:17 2017 +0300
@@ -62,13 +62,22 @@
 
 
 def import_hook(script, gnulib, namespace, verbosity, options, *args, **kwargs):
+    keywords = frozenset({
+        "tests",
+        "obsolete",
+        "cxx_tests",
+        "longrunning_tests",
+        "privileged_tests",
+        "unportable_tests",
+    })
     (_, _) = (args, kwargs)
     config = BaseConfig(**namespace)
     cache = CacheConfig(configure=None)
     for key in {"ac_version", "files"}:
         if key not in namespace:
             config[key] = cache[key]
-    (base, full, main, final, tests) = transitive_closure(gnulib.module, config.modules, config.options)
+    options = {key:config[key] for key in keywords}
+    (base, full, main, final, tests) = transitive_closure(gnulib.module, config.modules, **options)
 
     # Print some information about modules.
     print("Module list with included dependencies (indented):", file=sys.stdout)
--- a/pygnulib/config.py	Fri Oct 20 17:06:07 2017 +0300
+++ b/pygnulib/config.py	Fri Oct 20 20:24:17 2017 +0300
@@ -37,17 +37,6 @@
 })
 
 
-class Option:
-    """gnulib configuration options"""
-    Obsolete = (1 << 0)
-    Tests = (1 << 1)
-    CXX = (1 << 2)
-    Longrunning = (1 << 3)
-    Privileged = (1 << 4)
-    Unportable = (1 << 5)
-    All = (Obsolete | Tests | CXX | Longrunning | Privileged | Unportable)
-
-
 
 class Base:
     """gnulib generic configuration"""
@@ -66,13 +55,6 @@
         "po_domain"         : "",
         "witness_c_macro"   : "",
         "licenses"          : set(),
-        "tests"             : False,
-        "obsolete"          : False,
-        "cxx_tests"         : False,
-        "longrunning_tests" : False,
-        "privileged_tests"  : False,
-        "unportable_tests"  : False,
-        "all_tests"         : False,
         "libtool"           : False,
         "conddeps"          : False,
         "vc_files"          : False,
@@ -81,10 +63,29 @@
         "avoid"             : set(),
         "files"             : set(),
     }
+    _OPTIONS_ = frozenset({
+        "tests",
+        "obsolete",
+        "cxx_tests",
+        "longrunning_tests",
+        "privileged_tests",
+        "unportable_tests",
+    })
+
+
+    class _Option_:
+        """gnulib configuration options"""
+        Obsolete = (1 << 0)
+        Tests = (1 << 1)
+        CXX = (1 << 2)
+        Longrunning = (1 << 3)
+        Privileged = (1 << 4)
+        Unportable = (1 << 5)
+        AllTests = (Obsolete | Tests | CXX | Longrunning | Privileged | Unportable)
 
 
     def __init__(self, **kwargs):
-        self.__table = {}
+        self.__table = {"options": 0}
         for (key, value) in Base._TABLE_.items():
             self[key] = kwargs.get(key, value)
 
@@ -286,105 +287,98 @@
     @property
     def tests(self):
         """include unit tests for the included modules"""
-        return self.__table["tests"]
+        return bool(self.__table["options"] & Base._Option_.Tests)
 
     @tests.setter
     def tests(self, value):
         _type_assert_("tests", value, bool)
-        self.__table["tests"] = value
+        if value:
+            self.__table["options"] |= Base._Option_.Tests
+        else:
+            self.__table["options"] &= ~Base._Option_.Tests
 
 
     @property
     def obsolete(self):
         """include obsolete modules when they occur among the modules"""
-        return self.__table["obsolete"]
+        return bool(self.__table["options"] & Base._Option_.Tests)
 
     @obsolete.setter
     def obsolete(self, value):
         _type_assert_("obsolete", value, bool)
-        self.__table["obsolete"] = value
+        if value:
+            self.__table["options"] |= Base._Option_.Obsolete
+        else:
+            self.__table["options"] &= ~Base._Option_.Obsolete
 
 
     @property
     def cxx_tests(self):
         """include even unit tests for C++ interoperability"""
-        return self.__table["cxx_tests"]
+        return bool(self.__table["options"] & Base._Option_.CXX)
 
     @cxx_tests.setter
     def cxx_tests(self, value):
         _type_assert_("cxx_tests", value, bool)
-        self.__table["cxx_tests"] = value
+        if value:
+            self.__table["options"] |= Base._Option_.CXX
+        else:
+            self.__table["options"] &= ~Base._Option_.CXX
 
 
     @property
     def longrunning_tests(self):
         """include even unit tests that are long-runners"""
-        return self.__table["longrunning_tests"]
+        return bool(self.__table["options"] & Base._Option_.Longrunning)
 
     @longrunning_tests.setter
     def longrunning_tests(self, value):
         _type_assert_("longrunning_tests", value, bool)
-        self.__table["longrunning_tests"] = value
+        if value:
+            self.__table["options"] |= Base._Option_.Longrunning
+        else:
+            self.__table["options"] &= ~Base._Option_.Longrunning
 
 
     @property
     def privileged_tests(self):
         """include even unit tests that require root privileges"""
-        return self.__table["privileged_tests"]
+        return bool(self.__table["options"] & Base._Option_.Privileged)
 
     @privileged_tests.setter
     def privileged_tests(self, value):
         _type_assert_("privileged_tests", value, bool)
-        self.__table["privileged_tests"] = value
+        if value:
+            self.__table["options"] |= Base._Option_.Privileged
+        else:
+            self.__table["options"] &= ~Base._Option_.Privileged
 
 
     @property
     def unportable_tests(self):
         """include even unit tests that fail on some platforms"""
-        return self.__table["unportable_tests"]
+        return bool(self.__table["options"] & Base._Option_.Unportable)
 
     @unportable_tests.setter
     def unportable_tests(self, value):
         _type_assert_("unportable_tests", value, bool)
-        self.__table["unportable_tests"] = value
+        if value:
+            self.__table["options"] |= Base._Option_.Unportable
+        else:
+            self.__table["options"] &= ~Base._Option_.Unportable
 
 
     @property
     def all_tests(self):
         """include all kinds of problematic unit tests"""
-        result = True
-        result &= self.tests
-        result &= self.cxx_tests
-        result &= self.privileged_tests
-        result &= self.unportable_tests
-        result &= self.longrunning_tests
-        return result
+        return (self.__table["options"] & Base._Option_.AllTests) == Base._Option_.AllTests
 
     @all_tests.setter
     def all_tests(self, value):
-        self.__table["tests"] = value
-        self.__table["cxx_tests"] = value
-        self.__table["privileged_tests"] = value
-        self.__table["unportable_tests"] = value
-        self.__table["longrunning_tests"] = value
-
-    @property
-    def options(self):
-        """bitmask of active options"""
-        result = 0
-        if self.obsolete:
-            result |= Option.Obsolete
-        if self.tests:
-            result |= Option.Tests
-        if self.cxx_tests:
-            result |= Option.CXX
-        if self.longrunning_tests:
-            result |= Option.Longrunning
-        if self.privileged_tests:
-            result |= Option.Privileged
-        if self.unportable_tests:
-            result |= Option.Unportable
-        return result
+        if value:
+            self.__table["options"] |= Base._Option_.AllTests
+        else:
+            self.__table["options"] &= Base._Option_.AllTests
 
 
     @property
@@ -489,17 +483,19 @@
 
 
     def __getitem__(self, key):
-        if key not in Base._TABLE_:
+        table = (set(Base._TABLE_.keys()) | Base._OPTIONS_)
+        if key not in table:
             key = key.replace("-", "_")
-            if key not in Base._TABLE_:
+            if key not in table:
                 raise KeyError("unsupported option: {0}".format(key))
         return getattr(self, key)
 
 
     def __setitem__(self, key, value):
-        if key not in Base._TABLE_:
+        table = (set(Base._TABLE_.keys()) | Base._OPTIONS_)
+        if key not in table:
             key = key.replace("_", "-")
-            if key not in Base._TABLE_:
+            if key not in table:
                 raise KeyError("unsupported option: {0}".format(key))
         return setattr(self, key, value)
 
--- a/pygnulib/module.py	Fri Oct 20 17:06:07 2017 +0300
+++ b/pygnulib/module.py	Fri Oct 20 20:24:17 2017 +0300
@@ -13,7 +13,6 @@
 
 from .error import type_assert as _type_assert_
 from .error import UnknownModuleError as _UnknownModuleError_
-from .config import Option as _ConfigOption_
 
 
 
@@ -450,7 +449,7 @@
 
 
 
-def transitive_closure(lookup, modules, options):
+def transitive_closure(lookup, modules, **options):
     """
     Perform a transitive closure, generating a set of module dependencies.
     Each iteration over the table yields a tuple of (module, demander, condition).
@@ -462,27 +461,29 @@
     modules is an iterable, yielding a module (either name or instance).
     options may be any combination of gnulib configuration options.
     """
+    keywords = frozenset({
+        "tests",
+        "obsolete",
+        "cxx_tests",
+        "longrunning_tests",
+        "privileged_tests",
+        "unportable_tests",
+    })
     if not callable(lookup):
         raise TypeError("lookup must be a callable")
-    _type_assert_("options", options, int)
-    if options & ~_ConfigOption_.All:
-        raise ValueError("unknown configuration options")
-
-    obsolete = bool(options & _ConfigOption_.Obsolete)
-    tests = bool(options & _ConfigOption_.Tests)
-    cxx_tests = bool(options & _ConfigOption_.CXX)
-    longrunning_tests = bool(options & _ConfigOption_.Longrunning)
-    privileged_tests = bool(options & _ConfigOption_.Privileged)
-    unportable_tests = bool(options & _ConfigOption_.Unportable)
+    for (key, value) in options.items():
+        if key not in keywords:
+            return KeyError(key)
+        _type_assert_("option", value, bool)
     modules = set(lookup(module) for module in modules)
 
     def _exclude_(module):
         return any((
-            (not obsolete and module.obsolete),
-            (not cxx_tests and module.cxx_test),
-            (not longrunning_tests and module.longrunning_test),
-            (not privileged_tests and module.privileged_test),
-            (not unportable_tests and module.unportable_test),
+            (not options.get("obsolete", False) and module.obsolete),
+            (not options.get("cxx_tests", False) and module.cxx_test),
+            (not options.get("longrunning_tests", False) and module.longrunning_test),
+            (not options.get("privileged_tests", False) and module.privileged_test),
+            (not options.get("unportable_tests", False) and module.unportable_test),
         ))
 
     def _transitive_closure_(tests):
@@ -513,9 +514,9 @@
 
     base = _transitive_closure_(False)
     full = _transitive_closure_(True)
-    ignore = {"main"} if tests else {"main", "all"}
     main = {module for (module, _, _) in base}
-    final = {module for (module, _, _) in full} if tests else set(main)
+    final = {module for (module, _, _) in full} if options.get("tests", False) else set(main)
+    ignore = frozenset({"main"} if options.get("tests", False) else {"main", "all"})
     tests = (final - {module for module in main if module.applicability in ignore})
     return (base, full, main, final, tests)