mς ’%άGc@srdZdkZdkZdklZdkTdefd„ƒYZdefd„ƒYZdefd „ƒYZ dS( sttopological sorting algorithms. the key to the unit of work is to assemble a list of dependencies amongst all the different mappers that have been defined for classes. Related tables with foreign key constraints have a definite insert order, deletion order, objects need dependent properties from parent objects set up before saved, etc. These are all encoded as dependencies, in the form "mapper X is dependent on mapper Y", meaning mapper Y's objects must be saved before those of mapper X, and mapper X's objects must be deleted before those of mapper Y. The topological sort is an algorithm that receives this list of dependencies as a "partial ordering", that is a list of pairs which might say, "X is dependent on Y", "Q is dependent on Z", but does not necessarily tell you anything about Q being dependent on X. Therefore, its not a straight sort where every element can be compared to another...only some of the elements have any sorting preference, and then only towards just some of the other elements. For a particular partial ordering, there can be many possible sorts that satisfy the conditions. An intrinsic "gotcha" to this algorithm is that since there are many possible outcomes to sorting a partial ordering, the algorithm can return any number of different results for the same input; just running it on a different machine architecture, or just random differences in the ordering of dictionaries, can change the result that is returned. While this result is guaranteed to be true to the incoming partial ordering, if the partial ordering itself does not properly represent the dependencies, code that works fine will suddenly break, then work again, then break, etc. Most of the bugs I've chased down while developing the "unit of work" have been of this nature - very tricky to reproduce and track down, particularly before I realized this characteristic of the algorithm. N(sutil(t*t_NodecBs>tZdZd„Zd„Zdd„Zd„Zd„ZRS(sζrepresents each item in the sort. While the topological sort produces a straight ordered list of items, _Node ultimately stores a tree-structure of those items which are organized so that non-dependent nodes are siblings.cCs.||_tiƒ|_g|_d|_dS(N(titemtselftutiltSett dependenciestchildrentNonetcycles(RR((t:/home/holguin2/public_html/spyce/sqlalchemy/topological.pyt__init__)s  cCs |iƒS(N(Rtsafestr(R((R t__str__.sicCsŸd|dt|iƒ|idj o3dtg}|iD] }||q<~ƒdpddt i g}|i D]}||i |dƒqw~dƒS(Nt is (cycles: t)ts i(tindenttstrRRR Rtreprt_[1]txtstringtjoinRtnR (RRRRR((R R 0scCsdt|iƒS(Ns%s(RRR(R((R t__repr__6scCs|idj o0x-|iD]}||ijotSqqWn|idj o0x-|iD]}||ijotSqZqZWn||ijS(N(RR RtctchildRtTrue(RRR((R t is_dependent8s  (t__name__t __module__t__doc__R R R RR(((R R%s     t_EdgeCollectioncBshtZdZd„Zd„Zd„Zd„Zd„Zd„Zd„Z d„Z d „Z d „Z RS( sa collection of directed edges.cCsh|_h|_dS(N(Rtparent_to_childrentchild_to_parents(R((R R Es cCsœ|\}}|ii|ƒptiƒ|i|RGRR&RIR;RBRR$R?RDR ((R tsort‚sx M       #$  cs+dd‡‡‡d†‰‡d†‰ˆƒS(s­given a list of nodes from a topological sort, organizes the nodes into a tree structure, with as many non-dependent nodes set as silbings to each other as possible.csΔ|djo d}n|tˆƒjodSnˆ|}g}ˆ|d|ƒxL|D]D}|djpˆ||ƒo|i i |ƒqZ|i |ƒqZW|dj o|i |ƒn|S(Nii( tindexRR*R=R+tl2RLRtlt search_depRRC(RMROR+RRN(RPRLR=(R RLΗs    csm|djotSnU|i|ƒotSn=x9|iD]*}ˆ||ƒ}|tjotSq7q7WtSdS(N( RRtFalseR6RRRRRPR(R6RRR(RP(R RPΪs    N(RRLRP(RR=RLRP((R=RLRPR RKΔs c #sκtiƒ‰h‰dd‡‡‡‡d†‰xˆiƒD]}ˆ|ƒq:Wx•t g}ˆi ƒD]}|t |ƒ|fqe~ƒi ƒD]T} g}xAˆD]9}|d| jo"|d| jo|i|ƒq‘q‘W|VqŽWdS(Nc s6|djo|}g}n||jotSnxύˆi|ƒD]μ\}}||joqBn|i |ƒˆ|||ƒo’t i |ƒ}x|D]„}ˆi|ƒˆi|ƒoWˆ|} g}|D]}|| i|ƒqΠ~x| D]}| ˆ|R-RtkeyRCttraverseRRtcycsetRtinvolved_in_cyclesR(R R't existing_setRtyR0( R+RRRGRRURRSRXRRW(RVRTR>R (R RTλs0        ( ii(RRRVR RRTR>R/R6tdictRR3tstidRGtedgecollectionR$RC( RR>RRTR\R6R$RZRVR RG((R>RVRTR R RFθs  @"( RRR R RRQRLRKRF(((R R9ys  B $( R RtStringIOt sqlalchemyRtsqlalchemy.exceptionstobjectRR!R9(RR!R9RRR]((R t? s  6