| 1 | # orm/uowdumper.py |
|---|
| 2 | # Copyright (C) 2005, 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com |
|---|
| 3 | # |
|---|
| 4 | # This module is part of SQLAlchemy and is released under |
|---|
| 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php |
|---|
| 6 | |
|---|
| 7 | """Dumps out a string representation of a UOWTask structure""" |
|---|
| 8 | |
|---|
| 9 | from sqlalchemy.orm import unitofwork |
|---|
| 10 | from sqlalchemy.orm import util as mapperutil |
|---|
| 11 | import StringIO |
|---|
| 12 | |
|---|
| 13 | class UOWDumper(unitofwork.UOWExecutor): |
|---|
| 14 | def __init__(self, tasks, buf): |
|---|
| 15 | self.indent = 0 |
|---|
| 16 | self.tasks = tasks |
|---|
| 17 | self.buf = buf |
|---|
| 18 | self.execute(None, tasks) |
|---|
| 19 | |
|---|
| 20 | @classmethod |
|---|
| 21 | def dump(cls, tasks): |
|---|
| 22 | buf = StringIO.StringIO() |
|---|
| 23 | UOWDumper(tasks, buf) |
|---|
| 24 | return buf.getvalue() |
|---|
| 25 | |
|---|
| 26 | def execute(self, trans, tasks, isdelete=None): |
|---|
| 27 | if isdelete is not True: |
|---|
| 28 | for task in tasks: |
|---|
| 29 | self._execute(trans, task, False) |
|---|
| 30 | if isdelete is not False: |
|---|
| 31 | for task in reversed(tasks): |
|---|
| 32 | self._execute(trans, task, True) |
|---|
| 33 | |
|---|
| 34 | def _execute(self, trans, task, isdelete): |
|---|
| 35 | try: |
|---|
| 36 | i = self._indent() |
|---|
| 37 | if i: |
|---|
| 38 | i = i[:-1] + "+-" |
|---|
| 39 | self.buf.write(i + " " + self._repr_task(task)) |
|---|
| 40 | self.buf.write(" (" + (isdelete and "delete " or "save/update ") + "phase) \n") |
|---|
| 41 | self.indent += 1 |
|---|
| 42 | super(UOWDumper, self).execute(trans, [task], isdelete) |
|---|
| 43 | finally: |
|---|
| 44 | self.indent -= 1 |
|---|
| 45 | |
|---|
| 46 | |
|---|
| 47 | def save_objects(self, trans, task): |
|---|
| 48 | for rec in sorted(task.polymorphic_tosave_elements, key=lambda a: a.state.sort_key): |
|---|
| 49 | if rec.listonly: |
|---|
| 50 | continue |
|---|
| 51 | self.buf.write(self._indent()[:-1] + "+-" + self._repr_task_element(rec) + "\n") |
|---|
| 52 | |
|---|
| 53 | def delete_objects(self, trans, task): |
|---|
| 54 | for rec in task.polymorphic_todelete_elements: |
|---|
| 55 | if rec.listonly: |
|---|
| 56 | continue |
|---|
| 57 | self.buf.write(self._indent() + "- " + self._repr_task_element(rec) + "\n") |
|---|
| 58 | |
|---|
| 59 | def execute_dependency(self, transaction, dep, isdelete): |
|---|
| 60 | self._dump_processor(dep, isdelete) |
|---|
| 61 | |
|---|
| 62 | def _dump_processor(self, proc, deletes): |
|---|
| 63 | if deletes: |
|---|
| 64 | val = proc.targettask.polymorphic_todelete_elements |
|---|
| 65 | else: |
|---|
| 66 | val = proc.targettask.polymorphic_tosave_elements |
|---|
| 67 | |
|---|
| 68 | for v in val: |
|---|
| 69 | self.buf.write(self._indent() + " +- " + self._repr_task_element(v, proc.processor.key, process=True) + "\n") |
|---|
| 70 | |
|---|
| 71 | def _repr_task_element(self, te, attribute=None, process=False): |
|---|
| 72 | if getattr(te, 'state', None) is None: |
|---|
| 73 | objid = "(placeholder)" |
|---|
| 74 | else: |
|---|
| 75 | if attribute is not None: |
|---|
| 76 | objid = "%s.%s" % (mapperutil.state_str(te.state), attribute) |
|---|
| 77 | else: |
|---|
| 78 | objid = mapperutil.state_str(te.state) |
|---|
| 79 | if process: |
|---|
| 80 | return "Process %s" % (objid) |
|---|
| 81 | else: |
|---|
| 82 | return "%s %s" % ((te.isdelete and "Delete" or "Save"), objid) |
|---|
| 83 | |
|---|
| 84 | def _repr_task(self, task): |
|---|
| 85 | if task.mapper is not None: |
|---|
| 86 | if task.mapper.__class__.__name__ == 'Mapper': |
|---|
| 87 | name = task.mapper.class_.__name__ + "/" + task.mapper.local_table.description |
|---|
| 88 | else: |
|---|
| 89 | name = repr(task.mapper) |
|---|
| 90 | else: |
|---|
| 91 | name = '(none)' |
|---|
| 92 | return ("UOWTask(%s, %s)" % (hex(id(task)), name)) |
|---|
| 93 | |
|---|
| 94 | def _repr_task_class(self, task): |
|---|
| 95 | if task.mapper is not None and task.mapper.__class__.__name__ == 'Mapper': |
|---|
| 96 | return task.mapper.class_.__name__ |
|---|
| 97 | else: |
|---|
| 98 | return '(none)' |
|---|
| 99 | |
|---|
| 100 | def _indent(self): |
|---|
| 101 | return " |" * self.indent |
|---|