Logo Search packages:      
Sourcecode: sqlalchemy version File versions  Download package

def sqlalchemy::orm::unitofwork::UOWTask::_sort_circular_dependencies (   self,
  trans,
  cycles 
) [private]

for a single task, creates a hierarchical tree of "subtasks" which associate
specific dependency actions with individual objects.  This is used for a
"cyclical" task, or a task where elements
of its object list contain dependencies on each other.

this is not the normal case; this logic only kicks in when something like 
a hierarchical tree is being represented.

Definition at line 530 of file unitofwork.py.

00530                                                         :
        """for a single task, creates a hierarchical tree of "subtasks" which associate
        specific dependency actions with individual objects.  This is used for a
        "cyclical" task, or a task where elements
        of its object list contain dependencies on each other.

        this is not the normal case; this logic only kicks in when something like 
        a hierarchical tree is being represented."""
        allobjects = []
        for task in cycles:
            allobjects += [e.obj for e in task.get_elements(polymorphic=True)]
        tuples = []

        cycles = util.Set(cycles)

        #print "BEGIN CIRC SORT-------"
        #print "PRE-CIRC:"
        #print list(cycles) #[0].dump()

        # dependency processors that arent part of the cyclical thing
        # get put here
        extradeplist = []

        # organizes a set of new UOWTasks that will be assembled into
        # the final tree, for the purposes of holding new UOWDependencyProcessors
        # which process small sub-sections of dependent parent/child operations
        dependencies = {}
        def get_dependency_task(obj, depprocessor):
            try:
                dp = dependencies[obj]
            except KeyError:
                dp = dependencies.setdefault(obj, {})
            try:
                l = dp[depprocessor]
            except KeyError:
                l = UOWTask(self.uowtransaction, depprocessor.targettask.mapper, circular_parent=self)
                dp[depprocessor] = l
            return l

        def dependency_in_cycles(dep):
            # TODO: make a simpler way to get at the "root inheritance" mapper
            proctask = trans.get_task_by_mapper(dep.processor.mapper.primary_mapper().base_mapper(), True)
            targettask = trans.get_task_by_mapper(dep.targettask.mapper.base_mapper(), True)
            return targettask in cycles and (proctask is not None and proctask in cycles)

        # organize all original UOWDependencyProcessors by their target task
        deps_by_targettask = {}
        for t in cycles:
            for task in t.polymorphic_tasks():
                for dep in task.dependencies:
                    if not dependency_in_cycles(dep):
                        extradeplist.append(dep)
                    for t in dep.targettask.polymorphic_tasks():
                        l = deps_by_targettask.setdefault(t, [])
                        l.append(dep)

        object_to_original_task = {}

        for t in cycles:
            for task in t.polymorphic_tasks():
                for taskelement in task.get_elements(polymorphic=False):
                    obj = taskelement.obj
                    object_to_original_task[obj] = task

                    for dep in deps_by_targettask.get(task, []):
                        # is this dependency involved in one of the cycles ?
                        if not dependency_in_cycles(dep):
                            continue
                        (processor, targettask) = (dep.processor, dep.targettask)
                        isdelete = taskelement.isdelete

                        # list of dependent objects from this object
                        childlist = dep.get_object_dependencies(obj, trans, passive=True)
                        if childlist is None:
                            continue
                        # the task corresponding to saving/deleting of those dependent objects
                        childtask = trans.get_task_by_mapper(processor.mapper.primary_mapper())

                        childlist = childlist.added_items() + childlist.unchanged_items() + childlist.deleted_items()

                        for o in childlist:

                            # other object is None.  this can occur if the relationship is many-to-one
                            # or one-to-one, and None was set.  the "removed" object will be picked
                            # up in this iteration via the deleted_items() part of the collection.
                            if o is None:
                                continue

                            # the other object is not in the UOWTransaction !  but if we are many-to-one,
                            # we need a task in order to attach dependency operations, so establish a "listonly"
                            # task
                            if not childtask.contains_object(o, polymorphic=True):
                                childtask.append(o, listonly=True)
                                object_to_original_task[o] = childtask

                            # create a tuple representing the "parent/child"
                            whosdep = dep.whose_dependent_on_who(obj, o)
                            if whosdep is not None:
                                # append the tuple to the partial ordering.
                                tuples.append(whosdep)

                                # create a UOWDependencyProcessor representing this pair of objects.
                                # append it to a UOWTask
                                if whosdep[0] is obj:
                                    get_dependency_task(whosdep[0], dep).append(whosdep[0], isdelete=isdelete)
                                else:
                                    get_dependency_task(whosdep[0], dep).append(whosdep[1], isdelete=isdelete)
                            else:
                                get_dependency_task(obj, dep).append(obj, isdelete=isdelete)

        #print "TUPLES", tuples
        head = DependencySorter(tuples, allobjects).sort()
        if head is None:
            return None

        #print str(head)

        # create a tree of UOWTasks corresponding to the tree of object instances
        # created by the DependencySorter
        def make_task_tree(node, parenttask, nexttasks):
            originating_task = object_to_original_task[node.item]
            t = nexttasks.get(originating_task, None)
            if t is None:
                t = UOWTask(self.uowtransaction, originating_task.mapper, circular_parent=self)
                nexttasks[originating_task] = t
                parenttask.append(None, listonly=False, isdelete=originating_task.objects[node.item].isdelete, childtask=t)
            t.append(node.item, originating_task.objects[node.item].listonly, isdelete=originating_task.objects[node.item].isdelete)

            if dependencies.has_key(node.item):
                for depprocessor, deptask in dependencies[node.item].iteritems():
                    t.cyclical_dependencies.add(depprocessor.branch(deptask))
            nd = {}
            for n in node.children:
                t2 = make_task_tree(n, t, nd)
            return t

        # this is the new "circular" UOWTask which will execute in place of "self"
        t = UOWTask(self.uowtransaction, self.mapper, circular_parent=self)

        # stick the non-circular dependencies and child tasks onto the new
        # circular UOWTask
        [t.dependencies.add(d) for d in extradeplist]
        t.childtasks = self.childtasks
        make_task_tree(head, t, {})
        #print t.dump()
        return t

    def dump(self):


Generated by  Doxygen 1.6.0   Back to index