From: Mike Bayer Date: Mon, 31 Oct 2005 00:14:01 +0000 (+0000) Subject: dependency sort....bleah X-Git-Tag: rel_0_1_0~410 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3f51e45483fb1f3c5b29b5473bd62e76ebd0e9af;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git dependency sort....bleah --- diff --git a/lib/sqlalchemy/mapper.py b/lib/sqlalchemy/mapper.py index b91095b50e..4fc5fbc8b4 100644 --- a/lib/sqlalchemy/mapper.py +++ b/lib/sqlalchemy/mapper.py @@ -911,7 +911,7 @@ class PropertyLoader(MapperProperty): for child in childlist.added_items(): self._synchronize(obj, child, None, False) if self.direction == PropertyLoader.LEFT: - uowcommit.register_object(child, sort=True) + uowcommit.register_object(child) if self.direction != PropertyLoader.RIGHT or len(childlist.added_items()) == 0: for child in childlist.deleted_items(): self._synchronize(obj, child, None, True) diff --git a/lib/sqlalchemy/objectstore.py b/lib/sqlalchemy/objectstore.py index 28c551a781..3d5b3851f1 100644 --- a/lib/sqlalchemy/objectstore.py +++ b/lib/sqlalchemy/objectstore.py @@ -324,7 +324,7 @@ class UOWTransaction(object): task.mapper.register_dependencies(self) head = self._sort_dependencies() - print "Task dump:\n" + head.dump() + #print "Task dump:\n" + head.dump() if head is not None: head.execute(self) @@ -408,7 +408,7 @@ class UOWTask(object): def is_empty(self): return len(self.objects) == 0 and len(self.dependencies) == 0 and len(self.childtasks) == 0 - def append(self, obj, listonly = False, childtask = None, isdelete = False, sort=False): + def append(self, obj, listonly = False, childtask = None, isdelete = False): """appends an object to this task, to be either saved or deleted depending on the 'isdelete' attribute of this UOWTask. 'listonly' indicates that the object should only be processed as a dependency and not actually saved/deleted. @@ -417,8 +417,6 @@ class UOWTask(object): tasks, to assign dependent operations at the per-object instead of per-task level.""" try: rec = self.objects[obj] - if sort: - self.objects.toend(obj) except KeyError: rec = UOWTaskElement(obj) self.objects[obj] = rec diff --git a/lib/sqlalchemy/util.py b/lib/sqlalchemy/util.py index 2f6abcccd8..bae5d6bad5 100644 --- a/lib/sqlalchemy/util.py +++ b/lib/sqlalchemy/util.py @@ -57,15 +57,6 @@ class OrderedDict(dict): self.list = [] dict.clear(self) - def toend(self, key): - # TODO: optimize this - try: - del self.list[self.list.index(key)] - self.list.append(key) - print "toend: " + repr(key) - except ValueError: - raise KeyError(key) - def update(self, dict): for key in dict.keys(): self.__setitem__(key, dict[key]) @@ -340,6 +331,7 @@ class DependencySorter(object): is marked as "circular", indicating the node is dependent on itself. """ class Node: + """represents a node in a tree. stores an 'item' which represents the dependent thing we are talking about. if node 'a' is an ancestor node of node 'b', it means 'a's item is *not* dependent on that of 'b'.""" def __init__(self, item): #print "new node on " + str(item) self.item = item @@ -347,10 +339,32 @@ class DependencySorter(object): self.parent = None self.circular = False def append(self, node): + """appends the given node as a child on this node. removes the node from its preexisting parent.""" if node.parent is not None: del node.parent.children[node] self.children.append(node) node.parent = self + def is_descendant_of(self, node): + """returns true if this node is a descendant of the given node""" + n = self + while n is not None: + if n is node: + return True + else: + n = n.parent + return False + def get_root(self): + """returns the highest ancestor node of this node, i.e. which has no parent""" + n = self + while n.parent is not None: + n = n.parent + return n + def get_highest_sibling(self, node): + """returns the highest ancestor node of this one which is either the root node, or the common parent of this node and the given node""" + n = self + while n.parent is not None and n.parent is not node.parent: + n = n.parent + return n def __str__(self): return self.safestr({}) def safestr(self, hash, indent = 0): @@ -385,28 +399,23 @@ class DependencySorter(object): # get child node childnode = nodes[child] - - # now see, if the parent is an ancestor of the child - c = childnode - while c is not None and c is not parentnode: - root = c - c = c.parent + + if parentnode.parent is childnode: + # check for "a switch" + t = parentnode.item + parentnode.item = childnode.item + childnode.item = t + nodes[parentnode.item] = parentnode + nodes[childnode.item] = childnode + elif parentnode.is_descendant_of(childnode): + # check for a line thats backwards with nodes in between, this is a + # circular dependency (although confirmation on this would be helpful) + raise "Circular dependency detected" + elif not childnode.is_descendant_of(parentnode): + # if relationship doesnt exist, connect nodes together + root = childnode.get_highest_sibling(parentnode) + parentnode.append(root) - # nope, so we have to move the child down from whereever - # it currently is to a child of the parent - if c is None: - if childnode.parent is None: - print "moving down " + str(childnode.item) + ", has no parent" - parentnode.append(childnode) - else: - print "item " + str(childnode.item) + " has a parent " + str(childnode.parent.item) - for c in parentnode.children: - c.parent = root - root.children.append(c) - del parentnode.children[c] - root.parent = parentnode - parentnode.children.append(root) - # now we have a collection of subtrees which represent dependencies. # go through the collection root nodes wire them together into one tree head = None diff --git a/test/dependency.py b/test/dependency.py index d08df45e93..5dbc9be4ac 100644 --- a/test/dependency.py +++ b/test/dependency.py @@ -59,31 +59,29 @@ class DependencySortTest(PersistTest): node3 = thingy('items') tuples = [ (node1, node2), - (node3, node2) + (node3, node2), + (node1,node3) ] -# head1 = util.DependencySorter(tuples, [node1, node2, node3]).sort() + head1 = util.DependencySorter(tuples, [node1, node2, node3]).sort() head2 = util.DependencySorter(tuples, [node3, node1, node2]).sort() - # head3 = util.DependencySorter(tuples, [node3, node2, node1]).sort() + head3 = util.DependencySorter(tuples, [node3, node2, node1]).sort() # TODO: figure out a "node == node2" function #self.assert_(str(head1) == str(head2) == str(head3)) - # print "\n" + str(head1) + print "\n" + str(head1) print "\n" + str(head2) - # print "\n" + str(head3) + print "\n" + str(head3) def testsort4(self): node1 = thingy('keywords') node2 = thingy('itemkeyowrds') node3 = thingy('items') - node4 = thingy('lala') - node5 = thingy('hoho') - + node4 = thingy('hoho') tuples = [ (node1, node2), - (node5, node3), - (node4, node2), - (node3, node2), - + (node4, node1), + (node1, node3), + (node3, node2) ] head = util.DependencySorter(tuples, []).sort() print "\n" + str(head)