Updated copyright blurbs in all files to '# Copyright'
[hooke.git] / hooke / util / pluggable.py
1 # Copyright
2
3 """`pluggable`
4 """
5
6 from ..util.graph import Node, Graph
7
8
9 class IsSubclass (object):
10     """A safe subclass comparator.
11     
12     Examples
13     --------
14
15     >>> class A (object):
16     ...     pass
17     >>> class B (A):
18     ...     pass
19     >>> C = 5
20     >>> is_subclass = IsSubclass(A)
21     >>> is_subclass(A)
22     True
23     >>> is_subclass = IsSubclass(A, blacklist=[A])
24     >>> is_subclass(A)
25     False
26     >>> is_subclass(B)
27     True
28     >>> is_subclass(C)
29     False
30     """
31     def __init__(self, base_class, blacklist=None):
32         self.base_class = base_class
33         if blacklist == None:
34             blacklist = []
35         self.blacklist = blacklist
36     def __call__(self, other):
37         try:
38             subclass = issubclass(other, self.base_class)
39         except TypeError:
40             return False
41         if other in self.blacklist:
42             return False
43         return subclass
44
45 def construct_graph(this_modname, submodnames, class_selector,
46                     assert_name_match=True):
47     """Search the submodules `submodnames` of a module `this_modname`
48     for class objects for which `class_selector(class)` returns
49     `True`.  These classes are instantiated, and the `instance.name`
50     is compared to the `submodname` (if `assert_name_match` is
51     `True`).
52
53     The instances are further arranged into a dependency
54     :class:`hooke.util.graph.Graph` according to their
55     `instance.dependencies()` values.  The topologically sorted graph
56     is returned.
57     """
58     instances = {}
59     for submodname in submodnames:
60         count = len([s for s in submodnames if s == submodname])
61         assert count > 0, 'No %s entries: %s' % (submodname, submodnames)
62         assert count == 1, 'Multiple (%d) %s entries: %s' \
63             % (count, submodname, submodnames)
64         this_mod = __import__(this_modname, fromlist=[submodname])
65         submod = getattr(this_mod, submodname)
66         for objname in dir(submod):
67             obj = getattr(submod, objname)
68             if class_selector(obj):
69                 instance = obj()
70                 if assert_name_match == True and instance.name != submodname:
71                     raise Exception(
72                         'Instance name %s does not match module name %s'
73                         % (instance.name, submodname))
74                 instances[instance.name] = instance
75     nodes = {}
76     for i in instances.values():     # make nodes for each instance
77         nodes[i.name] = Node(data=i)
78     for n in nodes.values():         # fill in dependencies for each node
79         n.extend([nodes[name] for name in n.data.dependencies()])
80     graph = Graph(nodes.values())
81     graph.topological_sort()
82     return graph