[Sqlalchemy-commits] [1278] sqlalchemy/trunk: had to take out the "treeification" of the dependency
Brought to you by:
zzzeek
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1278] sqlalchemy/trunk: had to take out the "treeification" of the dependency sort as it doenst really work , added test conditions to the dependency test + the original test that failed</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1278</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-14 13:11:54 -0500 (Fri, 14 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>had to take out the "treeification" of the dependency sort as it doenst really work , added test conditions to the dependency test + the original test that failed</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunkCHANGES">sqlalchemy/trunk/CHANGES</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingtopologicalpy">sqlalchemy/trunk/lib/sqlalchemy/mapping/topological.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingunitofworkpy">sqlalchemy/trunk/lib/sqlalchemy/mapping/unitofwork.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemysqlpy">sqlalchemy/trunk/lib/sqlalchemy/sql.py</a></li> <li><a href="#sqlalchemytrunktestdependencypy">sqlalchemy/trunk/test/dependency.py</a></li> </ul> <h3>Added Paths</h3> <ul> <li><a href="#sqlalchemytrunktestrelationshipspy">sqlalchemy/trunk/test/relationships.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkCHANGES"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/CHANGES (1277 => 1278)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/CHANGES 2006-04-12 19:41:39 UTC (rev 1277) +++ sqlalchemy/trunk/CHANGES 2006-04-14 18:11:54 UTC (rev 1278) </span><span class="lines">@@ -1,3 +1,6 @@ </span><ins>+next +- some fixes to topological sort algorithm + </ins><span class="cx"> 0.1.6 </span><span class="cx"> - support for MS-SQL added courtesy Rick Morrison, Runar Petursson </span><span class="cx"> - the latest SQLSoup from J. Ellis </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingtopologicalpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/topological.py (1277 => 1278)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/topological.py 2006-04-12 19:41:39 UTC (rev 1277) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/topological.py 2006-04-14 18:11:54 UTC (rev 1278) </span><span class="lines">@@ -141,15 +141,16 @@ </span><span class="cx"> #print repr(output) </span><span class="cx"> head = None </span><span class="cx"> node = None </span><ins>+ # put the sorted list into a "tree". this is not much of a + # "tree" at the moment as its more of a linked list. it would be nice + # to group non-dependent nodes into sibling nodes, which allows better batching + # of SQL statements, but this algorithm has proved tricky </ins><span class="cx"> for o in output: </span><span class="cx"> if head is None: </span><span class="cx"> head = o </span><del>- node = o </del><span class="cx"> else: </span><del>- for x in node.children: - if x.dependencies.has_key(o): - node = x </del><span class="cx"> node.children.append(o) </span><ins>+ node = o </ins><span class="cx"> return head </span><span class="cx"> </span><span class="cx"> def _add_edge(self, edges, edge): </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingunitofworkpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/unitofwork.py (1277 => 1278)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/unitofwork.py 2006-04-12 19:41:39 UTC (rev 1277) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/unitofwork.py 2006-04-14 18:11:54 UTC (rev 1278) </span><span class="lines">@@ -422,7 +422,6 @@ </span><span class="cx"> mappers = util.HashSet() </span><span class="cx"> for task in self.tasks.values(): </span><span class="cx"> mappers.append(task.mapper) </span><del>- </del><span class="cx"> head = DependencySorter(self.dependencies, mappers).sort(allow_all_cycles=True) </span><span class="cx"> #print str(head) </span><span class="cx"> task = sort_hier(head) </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/sql.py (1277 => 1278)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-04-12 19:41:39 UTC (rev 1277) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-04-14 18:11:54 UTC (rev 1278) </span><span class="lines">@@ -917,7 +917,6 @@ </span><span class="cx"> def __init__(self, left, right, onclause=None, isouter = False): </span><span class="cx"> self.left = left </span><span class="cx"> self.right = right </span><del>- </del><span class="cx"> # TODO: if no onclause, do NATURAL JOIN </span><span class="cx"> if onclause is None: </span><span class="cx"> self.onclause = self._match_primaries(left, right) </span><span class="lines">@@ -925,6 +924,8 @@ </span><span class="cx"> self.onclause = onclause </span><span class="cx"> self.isouter = isouter </span><span class="cx"> </span><ins>+ name = property(lambda self: "Join on %s, %s" % (self.left.name, self.right.name)) + </ins><span class="cx"> def _locate_oid_column(self): </span><span class="cx"> return self.left.oid_column </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunktestdependencypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/dependency.py (1277 => 1278)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/dependency.py 2006-04-12 19:41:39 UTC (rev 1277) +++ sqlalchemy/trunk/test/dependency.py 2006-04-14 18:11:54 UTC (rev 1278) </span><span class="lines">@@ -17,6 +17,26 @@ </span><span class="cx"> return repr(self) </span><span class="cx"> </span><span class="cx"> class DependencySortTest(PersistTest): </span><ins>+ + def _assert_sort(self, tuples, allnodes, **kwargs): + + head = DependencySorter(tuples, allnodes).sort(**kwargs) + + print "\n" + str(head) + def findnode(t, n, parent=False): + if n.item is t[0]: + parent=True + elif n.item is t[1]: + if not parent and t[0] not in [c.item for c in n.cycles]: + self.assert_(False, "Node " + str(t[1]) + " not a child of " +str(t[0])) + else: + return + for c in n.children: + findnode(t, c, parent) + + for t in tuples: + findnode(t, head) + </ins><span class="cx"> def testsort(self): </span><span class="cx"> rootnode = thingy('root') </span><span class="cx"> node2 = thingy('node2') </span><span class="lines">@@ -27,6 +47,7 @@ </span><span class="cx"> subnode3 = thingy('subnode3') </span><span class="cx"> subnode4 = thingy('subnode4') </span><span class="cx"> subsubnode1 = thingy('subsubnode1') </span><ins>+ allnodes = [rootnode, node2,node3,node4,subnode1,subnode2,subnode3,subnode4,subsubnode1] </ins><span class="cx"> tuples = [ </span><span class="cx"> (subnode3, subsubnode1), </span><span class="cx"> (node2, subnode1), </span><span class="lines">@@ -37,9 +58,9 @@ </span><span class="cx"> (node4, subnode3), </span><span class="cx"> (node4, subnode4) </span><span class="cx"> ] </span><del>- head = DependencySorter(tuples, []).sort() - print "\n" + str(head) </del><span class="cx"> </span><ins>+ self._assert_sort(tuples, allnodes) + </ins><span class="cx"> def testsort2(self): </span><span class="cx"> node1 = thingy('node1') </span><span class="cx"> node2 = thingy('node2') </span><span class="lines">@@ -55,8 +76,7 @@ </span><span class="cx"> (node5, node6), </span><span class="cx"> (node6, node2) </span><span class="cx"> ] </span><del>- head = DependencySorter(tuples, [node7]).sort() - print "\n" + str(head) </del><ins>+ self._assert_sort(tuples, [node1,node2,node3,node4,node5,node6,node7]) </ins><span class="cx"> </span><span class="cx"> def testsort3(self): </span><span class="cx"> ['Mapper|Keyword|keywords,Mapper|IKAssociation|itemkeywords', 'Mapper|Item|items,Mapper|IKAssociation|itemkeywords'] </span><span class="lines">@@ -68,15 +88,10 @@ </span><span class="cx"> (node3, node2), </span><span class="cx"> (node1,node3) </span><span class="cx"> ] </span><del>- head1 = DependencySorter(tuples, [node1, node2, node3]).sort() - head2 = DependencySorter(tuples, [node3, node1, node2]).sort() - head3 = DependencySorter(tuples, [node3, node2, node1]).sort() </del><ins>+ self._assert_sort(tuples, [node1, node2, node3]) + self._assert_sort(tuples, [node3, node1, node2]) + self._assert_sort(tuples, [node3, node2, node1]) </ins><span class="cx"> </span><del>- # TODO: figure out a "node == node2" function - #self.assert_(str(head1) == str(head2) == str(head3)) - print "\n" + str(head1) - print "\n" + str(head2) - print "\n" + str(head3) </del><span class="cx"> </span><span class="cx"> def testsort4(self): </span><span class="cx"> node1 = thingy('keywords') </span><span class="lines">@@ -89,8 +104,7 @@ </span><span class="cx"> (node1, node3), </span><span class="cx"> (node3, node2) </span><span class="cx"> ] </span><del>- head = DependencySorter(tuples, []).sort() - print "\n" + str(head) </del><ins>+ self._assert_sort(tuples, [node1,node2,node3,node4]) </ins><span class="cx"> </span><span class="cx"> def testsort5(self): </span><span class="cx"> # this one, depenending on the weather, </span><span class="lines">@@ -117,9 +131,22 @@ </span><span class="cx"> node3, </span><span class="cx"> node4 </span><span class="cx"> ] </span><del>- head = DependencySorter(tuples, allitems).sort() - print "\n" + str(head) </del><ins>+ self._assert_sort(tuples, allitems) </ins><span class="cx"> </span><ins>+ def testsort6(self): + #('tbl_c', 'tbl_d'), ('tbl_a', 'tbl_c'), ('tbl_b', 'tbl_d') + nodea = thingy('tbl_a') + nodeb = thingy('tbl_b') + nodec = thingy('tbl_c') + noded = thingy('tbl_d') + tuples = [ + (nodec, noded), + (nodea, nodec), + (nodeb, noded) + ] + allitems = [nodea,nodeb,nodec,noded] + self._assert_sort(tuples, allitems) + </ins><span class="cx"> def testcircular(self): </span><span class="cx"> node1 = thingy('node1') </span><span class="cx"> node2 = thingy('node2') </span><span class="lines">@@ -134,8 +161,7 @@ </span><span class="cx"> (node3, node1), </span><span class="cx"> (node4, node1) </span><span class="cx"> ] </span><del>- head = DependencySorter(tuples, []).sort(allow_all_cycles=True) - print "\n" + str(head) </del><ins>+ self._assert_sort(tuples, [node1,node2,node3,node4,node5], allow_all_cycles=True) </ins><span class="cx"> </span><span class="cx"> </span><span class="cx"> if __name__ == "__main__": </span></span></pre></div> <a id="sqlalchemytrunktestrelationshipspy"></a> <div class="addfile"><h4>Added: sqlalchemy/trunk/test/relationships.py (1277 => 1278)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/relationships.py 2006-04-12 19:41:39 UTC (rev 1277) +++ sqlalchemy/trunk/test/relationships.py 2006-04-14 18:11:54 UTC (rev 1278) </span><span class="lines">@@ -0,0 +1,99 @@ </span><ins>+"""Test complex relationships""" + +import testbase +import unittest, sys, datetime + +db = testbase.db +#db.echo_uow=True + +from sqlalchemy import * + + +class RelationTest(testbase.PersistTest): + """this is essentially an extension of the "dependency.py" topological sort test. this exposes + a particular issue that doesnt always occur with the straight dependency tests, due to the nature + of the sort being different based on random conditions""" + def setUpAll(self): + testbase.db.tables.clear() + global tbl_a + global tbl_b + global tbl_c + global tbl_d + tbl_a = Table("tbl_a", db, + Column("id", Integer, primary_key=True), + Column("name", String), + ) + tbl_b = Table("tbl_b", db, + Column("id", Integer, primary_key=True), + Column("name", String), + ) + tbl_c = Table("tbl_c", db, + Column("id", Integer, primary_key=True), + Column("tbl_a_id", Integer, ForeignKey("tbl_a.id"), nullable=False), + Column("name", String), + ) + tbl_d = Table("tbl_d", db, + Column("id", Integer, primary_key=True), + Column("tbl_c_id", Integer, ForeignKey("tbl_c.id"), nullable=False), + Column("tbl_b_id", Integer, ForeignKey("tbl_b.id")), + Column("name", String), + ) + def setUp(self): + tbl_a.create() + tbl_b.create() + tbl_c.create() + tbl_d.create() + + objectstore.clear() + clear_mappers() + + class A(object): + pass + class B(object): + pass + class C(object): + pass + class D(object): + pass + + D.mapper = mapper(D, tbl_d) + C.mapper = mapper(C, tbl_c, properties=dict( + d_rows=relation(D, private=True, backref="c_row"), + )) + B.mapper = mapper(B, tbl_b) + A.mapper = mapper(A, tbl_a, properties=dict( + c_rows=relation(C, private=True, backref="a_row"), + )) + D.mapper.add_property("b_row", relation(B)) + + global a + global c + a = A(); a.name = "a1" + b = B(); b.name = "b1" + c = C(); c.name = "c1"; c.a_row = a + # we must have more than one d row or it won't fail + d = D(); d.name = "d1"; d.b_row = b; d.c_row = c + d = D(); d.name = "d2"; d.b_row = b; d.c_row = c + d = D(); d.name = "d3"; d.b_row = b; d.c_row = c + + def tearDown(self): + tbl_d.drop() + tbl_c.drop() + tbl_b.drop() + tbl_a.drop() + + def testDeleteRootTable(self): + session = objectstore.get_session() + session.commit() + session.delete(a) # works as expected + session.commit() + + def testDeleteMiddleTable(self): + session = objectstore.get_session() + session.commit() + session.delete(c) # fails + session.commit() + + +if __name__ == "__main__": + testbase.main() </ins></span></pre> </div> </div> </body> </html> |