simplify topological dependency solution

This patch prepares the way for simplifying the topological sort solution for
the classes which implement the document building logic.  Formerly, each
doctype class had to import networx itself and the @depends decorator stuffed
the dependencies into a graph in the class variable.

Now, each method tracks its dependencies (same decorator trick), but the
topological sort is not computed until just before running the job.  This is
more flexible, more obvious, simpler and features less code replication.

The next commit or two will convert the remaining doctype classes to use this
techinque.
This commit is contained in:
Martin A. Brown 2016-03-05 17:04:45 -08:00
parent 7d287b44e5
commit 4c01ae4af7
1 changed files with 22 additions and 11 deletions

View File

@ -8,6 +8,7 @@ import sys
import stat
import errno
import logging
import inspect
from tempfile import NamedTemporaryFile as ntf
from functools import wraps
import networkx as nx
@ -27,15 +28,13 @@ postamble = '''
'''
def depends(graph, *predecessors):
def depends(*predecessors):
'''decorator to be used for constructing build order graph'''
def anon(f):
for dep in predecessors:
graph.add_edge(dep.__name__, f.__name__)
@wraps(f)
def method(self, *args, **kwargs):
return f(self, *args, **kwargs)
method.depends = [x.__name__ for x in predecessors]
return method
return anon
@ -155,19 +154,31 @@ class BaseDoctype(object):
return False
return True
def determinebuildorder(self):
graph = nx.DiGraph()
d = dict(inspect.getmembers(self, inspect.ismethod))
for name, member in d.items():
predecessors = getattr(member, 'depends', None)
if predecessors:
for pred in predecessors:
method = d.get(pred, None)
assert method is not None
graph.add_edge(method, member)
order = nx.dag.topological_sort(graph)
return order
@logtimings(logger.debug)
def buildall(self):
stem = self.source.stem
order = nx.dag.topological_sort(self.graph)
order = self.determinebuildorder()
logger.debug("%s build order %r", self.source.stem, order)
for dep in order:
method = getattr(self, dep, None)
assert method is not None
for method in order:
classname = self.__class__.__name__
logger.info("%s calling method %s.%s", stem, classname, dep)
logger.info("%s calling method %s.%s",
stem, classname, method.__name__)
if not method():
logger.error("%s reported method %s failure, skipping...",
stem, dep)
logger.error("%s called method %s.%s failed, skipping...",
stem, classname, method.__name__)
return False
return True