from sqlalchemy.orm import unitofwork """dumps out a string representation of a UOWTask structure""" class UOWDumper(unitofwork.UOWExecutor): def __init__(self, task, buf, verbose=False): self.verbose = verbose self.indent = 0 self.task = task self.buf = buf self.starttask = task self.headers = {} self.execute(None, task) def execute(self, trans, task, isdelete=None): oldstarttask = self.starttask oldheaders = self.headers self.starttask = task self.headers = {} try: i = self._indent() if len(i): i += "-" #i = i[0:-1] + "-" if task.circular is not None: self.buf.write(self._indent() + "\n") self.buf.write(i + " " + self._repr_task(task)) self.buf.write(" (contains cyclical sub-tasks)") else: self.buf.write(self._indent() + "\n") self.buf.write(i + " " + self._repr_task(task)) self.buf.write(" (" + (isdelete and "delete " or "save/update ") + "phase) \n") self.indent += 1 super(UOWDumper, self).execute(trans, task, isdelete) finally: self.indent -= 1 if self.starttask.is_empty(): self.buf.write(self._indent() + " |- (empty task)\n") else: self.buf.write(self._indent() + " |----\n") self.buf.write(self._indent() + "\n") self.starttask = oldstarttask self.headers = oldheaders def save_objects(self, trans, task): # sort elements to be inserted by insert order def comparator(a, b): if a.obj is None: x = None elif not hasattr(a.obj, '_sa_insert_order'): x = None else: x = a.obj._sa_insert_order if b.obj is None: y = None elif not hasattr(b.obj, '_sa_insert_order'): y = None else: y = b.obj._sa_insert_order return cmp(x, y) l = list(task.polymorphic_tosave_elements) l.sort(comparator) for rec in l: if rec.listonly: continue self.header("Save elements"+ self._inheritance_tag(task)) self.buf.write(self._indent() + "- " + self._repr_task_element(rec) + "\n") self.closeheader() def delete_objects(self, trans, task): for rec in task.polymorphic_todelete_elements: if rec.listonly: continue self.header("Delete elements"+ self._inheritance_tag(task)) self.buf.write(self._indent() + "- " + self._repr_task_element(rec) + "\n") self.closeheader() def _inheritance_tag(self, task): if not self.verbose: return "" elif task is not self.starttask: return (" (inheriting task %s)" % self._repr_task(task)) else: return "" def header(self, text): """write a given header just once""" if not self.verbose: return try: self.headers[text] except KeyError: self.buf.write(self._indent() + "- " + text + "\n") self.headers[text] = True def closeheader(self): if not self.verbose: return self.buf.write(self._indent() + "- ------\n") def execute_dependency(self, transaction, dep, isdelete): self._dump_processor(dep, isdelete) def execute_save_steps(self, trans, task): super(UOWDumper, self).execute_save_steps(trans, task) def execute_delete_steps(self, trans, task): super(UOWDumper, self).execute_delete_steps(trans, task) def execute_dependencies(self, trans, task, isdelete=None): super(UOWDumper, self).execute_dependencies(trans, task, isdelete) def execute_childtasks(self, trans, task, isdelete=None): self.header("Child tasks" + self._inheritance_tag(task)) super(UOWDumper, self).execute_childtasks(trans, task, isdelete) self.closeheader() def execute_cyclical_dependencies(self, trans, task, isdelete): self.header("Cyclical %s dependencies" % (isdelete and "delete" or "save")) super(UOWDumper, self).execute_cyclical_dependencies(trans, task, isdelete) self.closeheader() def execute_per_element_childtasks(self, trans, task, isdelete): super(UOWDumper, self).execute_per_element_childtasks(trans, task, isdelete) def execute_element_childtasks(self, trans, element, isdelete): self.header("%s subelements of UOWTaskElement(%s)" % ((isdelete and "Delete" or "Save"), hex(id(element)))) super(UOWDumper, self).execute_element_childtasks(trans, element, isdelete) self.closeheader() def _dump_processor(self, proc, deletes): if deletes: val = proc.targettask.polymorphic_todelete_elements else: val = proc.targettask.polymorphic_tosave_elements if self.verbose: self.buf.write(self._indent() + " |- %s attribute on %s (UOWDependencyProcessor(%d) processing %s)\n" % ( repr(proc.processor.key), ("%s's to be %s" % (self._repr_task_class(proc.targettask), deletes and "deleted" or "saved")), hex(id(proc)), self._repr_task(proc.targettask)) ) elif False: self.buf.write(self._indent() + " |- %s attribute on %s\n" % ( repr(proc.processor.key), ("%s's to be %s" % (self._repr_task_class(proc.targettask), deletes and "deleted" or "saved")), ) ) if len(val) == 0: if self.verbose: self.buf.write(self._indent() + " |- " + "(no objects)\n") for v in val: self.buf.write(self._indent() + " |- " + self._repr_task_element(v, proc.processor.key, process=True) + "\n") def _repr_task_element(self, te, attribute=None, process=False): if te.obj is None: objid = "(placeholder)" else: if attribute is not None: objid = "%s(%s).%s" % (te.obj.__class__.__name__, hex(id(te.obj)), attribute) else: objid = "%s(%s)" % (te.obj.__class__.__name__, hex(id(te.obj))) if self.verbose: return "%s (UOWTaskElement(%s, %s))" % (objid, hex(id(te)), (te.listonly and 'listonly' or (te.isdelete and 'delete' or 'save'))) elif process: return "Process %s" % (objid) else: return "%s %s" % ((te.isdelete and "Delete" or "Save"), objid) def _repr_task(self, task): if task.mapper is not None: if task.mapper.__class__.__name__ == 'Mapper': name = task.mapper.class_.__name__ + "/" + task.mapper.local_table.name + "/" + str(task.mapper.entity_name) else: name = repr(task.mapper) else: name = '(none)' if task.circular_parent: return ("UOWTask(%s->%s, %s)" % (hex(id(task.circular_parent)), hex(id(task)), name)) else: return ("UOWTask(%s, %s)" % (hex(id(task)), name)) def _repr_task_class(self, task): if task.mapper is not None and task.mapper.__class__.__name__ == 'Mapper': return task.mapper.class_.__name__ else: return '(none)' def _repr(self, obj): return "%s(%s)" % (obj.__class__.__name__, hex(id(obj))) def _indent(self): return " |" * self.indent