mirror of https://github.com/tLDP/python-tldp
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:
parent
7d287b44e5
commit
4c01ae4af7
|
@ -8,6 +8,7 @@ import sys
|
||||||
import stat
|
import stat
|
||||||
import errno
|
import errno
|
||||||
import logging
|
import logging
|
||||||
|
import inspect
|
||||||
from tempfile import NamedTemporaryFile as ntf
|
from tempfile import NamedTemporaryFile as ntf
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
import networkx as nx
|
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'''
|
'''decorator to be used for constructing build order graph'''
|
||||||
def anon(f):
|
def anon(f):
|
||||||
for dep in predecessors:
|
|
||||||
graph.add_edge(dep.__name__, f.__name__)
|
|
||||||
|
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def method(self, *args, **kwargs):
|
def method(self, *args, **kwargs):
|
||||||
return f(self, *args, **kwargs)
|
return f(self, *args, **kwargs)
|
||||||
|
method.depends = [x.__name__ for x in predecessors]
|
||||||
return method
|
return method
|
||||||
return anon
|
return anon
|
||||||
|
|
||||||
|
@ -155,19 +154,31 @@ class BaseDoctype(object):
|
||||||
return False
|
return False
|
||||||
return True
|
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)
|
@logtimings(logger.debug)
|
||||||
def buildall(self):
|
def buildall(self):
|
||||||
stem = self.source.stem
|
stem = self.source.stem
|
||||||
order = nx.dag.topological_sort(self.graph)
|
order = self.determinebuildorder()
|
||||||
logger.debug("%s build order %r", self.source.stem, order)
|
logger.debug("%s build order %r", self.source.stem, order)
|
||||||
for dep in order:
|
for method in order:
|
||||||
method = getattr(self, dep, None)
|
|
||||||
assert method is not None
|
|
||||||
classname = self.__class__.__name__
|
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():
|
if not method():
|
||||||
logger.error("%s reported method %s failure, skipping...",
|
logger.error("%s called method %s.%s failed, skipping...",
|
||||||
stem, dep)
|
stem, classname, method.__name__)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue