From 34b85028c86708c48be78f8033c170a494a6d356 Mon Sep 17 00:00:00 2001 From: Dmitry Selyutin Date: Thu, 21 Dec 2017 00:57:56 +0300 Subject: [PATCH] module: module database implementation --- pygnulib.py | 2 +- pygnulib/module.py | 97 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/pygnulib.py b/pygnulib.py index e1f90c9bc8..d0acadda11 100755 --- a/pygnulib.py +++ b/pygnulib.py @@ -110,7 +110,7 @@ def import_hook(script, gnulib, namespace, explicit, verbosity, options, *args, if key not in namespace: config[key] = cache[key] test_options = {key:config[key] for key in keywords} - (base, full, main, final, tests) = transitive_closure(gnulib.module, config.modules, **test_options) + (db, main, final, tests) = transitive_closure(gnulib.module, config.modules, **test_options) # Print some information about modules. print("Module list with included dependencies (indented):", file=sys.stdout) diff --git a/pygnulib/module.py b/pygnulib/module.py index 674abfbc1f..6b35a04cb6 100644 --- a/pygnulib/module.py +++ b/pygnulib/module.py @@ -63,22 +63,11 @@ class Base: def __repr__(self): module = self.__class__.__module__ name = self.__class__.__name__ - return "{}.{}{}".format(module, name, repr(self.__table["name"])) + return "{}.{}<{}>".format(module, name, self.__table["name"]) def __str__(self): - result = "" - for (key, (_, typeid, field)) in sorted(Base._TABLE.items(), key=lambda k: k[1][0]): - field += ":\n" - if typeid in _ITERABLES: - value = "\n".join(self.__table[key]) - else: - value = self.__table[key] - if value: - result += field - result += value - result += "\n\n" if value else "\n" - return result.strip() + "\n" + return self.__table["name"] def __enter__(self): @@ -109,6 +98,22 @@ class Base: return setattr(self, key, value) + @property + def package(self): + result = "" + for (key, (_, typeid, field)) in sorted(Base._TABLE.items(), key=lambda k: k[1][0]): + field += ":\n" + if typeid in _ITERABLES: + value = "\n".join(self.__table[key]) + else: + value = self.__table[key] + if value: + result += field + result += value + result += "\n\n" if value else "\n" + return result.strip() + "\n" + + @property def name(self): """name""" @@ -532,10 +537,69 @@ class File(Base): +class Database: + """gnulib module database""" + _NONE_TYPE = type(None) + + + def __init__(self, table, lookup=None): + _type_assert("table", table, _ITERABLES) + if not (isinstance(lookup, Database._NONE_TYPE) or callable(lookup)): + raise TypeError("lookup must be a callable") + def _lookup(module): + if not isinstance(module, (Database._NONE_TYPE, Base)): + if isinstance(module, str): + module = lookup(module) + if not isinstance(module, Base): + raise TypeError("module: pygnulib.module.Base expected") + return module + def _raise(module): + raise TypeError("cannot instantiate the module") + self.__table = set() + self.__lookup = _lookup if lookup else _raise + for (dependency, demander, condition) in table: + dependency = self.__lookup(dependency) + demander = self.__lookup(demander) + if dependency is None: + raise TypeError("dependency: pygnulib.module.Base expected") + if not isinstance(condition, (str, Database._NONE_TYPE)): + raise TypeError("condition: str or None expected") + self.__table.add((dependency, demander, condition)) + self.__table = frozenset(self.__table) + + + def __repr__(self): + module = self.__class__.__module__ + name = self.__class__.__name__ + return "{}.{}".format(module, name, hex(id(self)), len(self.__table)) + + + def __iter__(self): + return iter(self.__table) + + + def demanders(self, module): + """For each demander which requires the module yield the demander and condition.""" + module = self.__lookup(module) + for (dependency, demander, condition) in self.__table: + if module == dependency: + yield (demander, condition) + + + def dependencies(self, module): + """For each dependency of this module yield the dependency and the condition.""" + module = self.__lookup(module) + for (dependency, demander, condition) in self.__table: + if module == demander: + yield (dependency, condition) + + + 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). + Perform a transitive closure, generating a set of module dependencies (database). + Each iteration over the database yields a tuple of (module, demander, condition). + At the same time return sets, which designate main, final and test modules respectively. If condition is None, but demander is not, there is no special condition for this module. If demander is None, the module is provided unconditionally (condition is always None). @@ -607,11 +671,12 @@ def transitive_closure(lookup, modules, **options): base = _transitive_closure_(False) full = _transitive_closure_(True) + table = Database((base | full), lookup) main = {module for (module, _, _) in base} 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) + return (table, main, final, tests) -- 2.39.5