[PATCH 6/6] Store and then write out the string representation of the traceback and object dump

Vratislav Podzimek vpodzime at redhat.com
Wed Jul 11 11:59:47 UTC 2012


We passed the filename of the file containing the traceback and object dump to
libreport, and MainExceptionWindow. But that meant libreport and MainExceptionWindow
had to read the file and save the content to its internal structure. We need to
write traceback and object dump to a file, but we can pass its contents as string
directly to libreport and MainExceptionWindow.

There is a related patch for libreport removing the glue reading the file contents.
---
 meh/dump.py        |  113 +++++++++++++++++++++++++++-------------------------
 meh/handler.py     |   10 +++-
 meh/ui/__init__.py |    6 +-
 meh/ui/gui.py      |   12 +----
 meh/ui/text.py     |    4 +-
 5 files changed, 74 insertions(+), 71 deletions(-)

diff --git a/meh/dump.py b/meh/dump.py
index 7e01d39..adfdb27 100644
--- a/meh/dump.py
+++ b/meh/dump.py
@@ -249,9 +249,9 @@ class ExceptionDump(object):
 
         return traceback.format_list(frames)
 
-    # Create a string representation of a class and write it to fd.  This
-    # method will recursively handle all attributes of the base given class.
-    def _dumpClass(self, instance, fd, level=0, parentkey="", skipList=[]):
+    # Create a string representation of a class.  This method will recursively
+    # handle all attributes of the base given class.
+    def _dumpClass(self, instance, level=0, parentkey="", skipList=[]):
         # This is horribly cheesy, and bound to require maintainence in the
         # future.  The problem is that anything subclassed from object fails
         # the types.InstanceType test we used to have which means those
@@ -266,6 +266,8 @@ class ExceptionDump(object):
                                       types.StringType, types.UnicodeType] or \
                    not hasattr(instance, "__class__")
 
+        ret = ""
+
         # protect from loops
         try:
             # Store the id(), not the instance name to protect against
@@ -273,23 +275,23 @@ class ExceptionDump(object):
             if not self._dumpHash.has_key(id(instance)):
                 self._dumpHash[id(instance)] = None
             else:
-                fd.write("Already dumped (%s instance)\n" % instance.__class__.__name__)
+                ret += "Already dumped (%s instance)\n" % instance.__class__.__name__
                 return
         except TypeError:
-            fd.write("Cannot dump object\n")
+            ret += "Cannot dump object\n"
             return
 
         if (instance.__class__.__dict__.has_key("__str__") or
             instance.__class__.__dict__.has_key("__repr__")):
             try:
-                fd.write("%s\n" % (instance,))
+                ret += "%s\n" % (instance,)
             except:
-                fd.write("\n")
+                ret += "\n"
 
             return
 
-        fd.write("%s instance, containing members:\n" %
-                 (instance.__class__.__name__))
+        ret += "%s instance, containing members:\n" %\
+                (instance.__class__.__name__)
         pad = ' ' * ((level) * 2)
 
         for key, value in instance.__dict__.items():
@@ -305,58 +307,60 @@ class ExceptionDump(object):
             # None are probably okay.
             if eval("instance.%s is not None" % key) and \
                eval("id(instance.%s)" % key) in skipList:
-                fd.write("%s%s: Skipped\n" % (pad, curkey))
+                ret += "%s%s: Skipped\n" % (pad, curkey)
                 continue
 
             if type(value) == types.ListType:
-                fd.write("%s%s: [" % (pad, curkey))
+                ret += "%s%s: [" % (pad, curkey)
                 first = 1
                 for item in value:
                     if not first:
-                        fd.write(", ")
+                        ret += ", "
                     else:
                         first = 0
 
                     if __isSimpleType(item):
-                        fd.write("%s" % (item,))
+                        ret += "%s" % (item,)
                     else:
-                        self._dumpClass(item, fd, level + 1, skipList=skipList)
-                fd.write("]\n")
+                        self._dumpClass(item, level + 1, skipList=skipList)
+                ret += "]\n"
             elif type(value) == types.DictType:
-                fd.write("%s%s: {" % (pad, curkey))
+                ret += "%s%s: {" % (pad, curkey)
                 first = 1
                 for k, v in value.items():
                     if not first:
-                        fd.write(", ")
+                        ret += ", "
                     else:
                         first = 0
                     if type(k) == types.StringType:
-                        fd.write("'%s': " % (k,))
+                        ret += "'%s': " % (k,)
                     else:
-                        fd.write("%s: " % (k,))
+                        ret += "%s: " % (k,)
 
                     if __isSimpleType(v):
-                        fd.write("%s" % (v,))
+                        ret += "%s" % (v,)
                     else:
-                        self._dumpClass(v, fd, level + 1, parentkey = curkey, skipList=skipList)
-                fd.write("}\n")
+                        self._dumpClass(v, level + 1, parentkey = curkey, skipList=skipList)
+                ret += "}\n"
             elif __isSimpleType(value):
-                fd.write("%s%s: %s\n" % (pad, curkey, value))
+                ret += "%s%s: %s\n" % (pad, curkey, value)
             else:
-                fd.write("%s%s: " % (pad, curkey))
-                self._dumpClass(value, fd, level + 1, parentkey=curkey, skipList=skipList)
+                ret += "%s%s: " % (pad, curkey)
+                self._dumpClass(value, level + 1, parentkey=curkey, skipList=skipList)
+
+        return ret
 
-    def dump(self, fd, obj):
-        """Dump the local variables and all attributes of a given object to an
-           open file descriptor.  The lists of files and attrs to ignore are
-           all taken from a Config object instance provided when the
-           ExceptionDump class was created.
+    def dump(self, obj):
+        """Dump the local variables and all attributes of a given object.
+           The lists of files and attrs to ignore are all taken from a
+           Config object instance provided when the ExceptionDump class was
+           created.
 
-           fd  -- An open file descriptor to write everything to.
            obj -- Any Python object.  This object will have all its attributes
                   written out, except for those mentioned in the attrSkipList.
         """
         idSkipList = []
+        ret = ""
 
         # We need to augment the environment eval() will run in with the
         # bindings that were local when the traceback happened so that the
@@ -376,39 +380,39 @@ class ExceptionDump(object):
         # Write local variables to the given file descriptor, ignoring any of
         # the local skips.
         frame = self.stack[-1][0]
-        fd.write ("\nLocal variables in innermost frame:\n")
+        ret += "\nLocal variables in innermost frame:\n"
         try:
             for (key, value) in frame.f_locals.items():
                 loweredKey = key.lower()
                 if len(filter(lambda s: loweredKey.find(s) != -1, self.conf.localSkipList)) > 0:
                     continue
 
-                fd.write ("%s: %s\n" % (key, value))
+                ret += "%s: %s\n" % (key, value)
         except:
             pass
 
         # And now dump the object's attributes.
         try:
-            fd.write("\n\n")
-            self._dumpClass(obj, fd, skipList=idSkipList)
+            ret += "\n\n"
+            ret += self._dumpClass(obj, skipList=idSkipList)
         except:
-            fd.write("\nException occurred during state dump:\n")
-            traceback.print_exc(None, fd)
+            ret += "\nException occurred during state dump:\n"
+            ret += traceback.format_exc(None)
 
         # And finally, write a bunch of files into the dump too.
-        for fn in self.conf.fileList:
+        for fname in self.conf.fileList:
             try:
-                f = open(fn, 'r')
-                line = "\n\n%s:\n" % (fn,)
-                while line:
-                    fd.write(line)
-                    line = f.readline()
-                f.close()
+                with open(fname, 'r') as fobj:
+                    ret += "\n\n%s:\n" % (fname,)
+                    for line in fobj:
+                        ret += line
             except IOError:
                 pass
             except:
-                fd.write("\nException occurred during %s file copy:\n" % (fn,))
-                traceback.print_exc(None, fd)
+                ret += "\nException occurred during %s file copy:\n" % (fname,)
+                ret += traceback.format_exc(None)
+
+        return ret
 
     @property
     def hash(self):
@@ -428,17 +432,18 @@ class ExceptionDump(object):
 
         return hashlib.sha256(s).hexdigest()
 
-    def write(self, obj, fd):
-        """Write the traceback and a text representation of an object to an
-           open file descriptor.
+    def traceback_and_object_dump(self, obj):
+        """
+        Return the traceback and a text representation of an object.
+
+        @param obj: Any Python object. This object will have all its attributes
+                    written out, except for those mentioned in the attrSkipList.
 
-           fd  -- An open file descriptor to write everything to.
-           obj -- Any Python object.  This object will have all its attributes
-                  written out, except for those mentioned in the attrSkipList.
         """
+
         ret = str(self)
-        fd.write(ret)
-        self.dump(fd, obj)
+        ret += self.dump(obj)
+
         return ret
 
 class ReverseExceptionDump(ExceptionDump):
diff --git a/meh/handler.py b/meh/handler.py
index 2a5bb76..befbcf8 100644
--- a/meh/handler.py
+++ b/meh/handler.py
@@ -54,6 +54,7 @@ class ExceptionHandler(object):
 
         self._exitcode = 10
         self._exn = None
+        self.exnText = ""
 
     def _setExitCode(self, code):
         self._exitcode = code
@@ -96,14 +97,15 @@ class ExceptionHandler(object):
         # Save the exception to the filesystem first.
         self.exn = self.exnClass((ty, value, tb), self.conf)
         (fd, self.exnFile) = self.openFile()
-        text = self.exn.write(obj, fd)
+        self.exnText = self.exn.traceback_and_object_dump(obj)
+        fd.write(self.exnText)
         fd.close()
 
         self.postWriteHook((ty, value, tb), obj)
 
         # Run initial UI screen, asking whether to save/debug/quit.
         while True:
-            win = self.intf.mainExceptionWindow(text, self.exnFile)
+            win = self.intf.mainExceptionWindow(str(self.exn), self.exnText)
             if not win:
                 self.runQuit((ty, value, tb))
 
@@ -209,7 +211,9 @@ class ExceptionHandler(object):
         params["reason"] = self.exn.desc
         params["description"] = "The following was filed automatically by %s:\n%s" \
                                     % (self.conf.programName, str(self.exn))
-        params["exnFileName"] = self.exnFile
+
+        tb_item_name = "%s-tb" % self.conf.programName
+        params[tb_item_name] = self.exnText
 
         accountManager = report.accountmanager.AccountManager()
 
diff --git a/meh/ui/__init__.py b/meh/ui/__init__.py
index 63980aa..295c133 100644
--- a/meh/ui/__init__.py
+++ b/meh/ui/__init__.py
@@ -77,7 +77,7 @@ class AbstractMainExceptionWindow(object):
        window is the initial dialog displayed by the exception handler that
        provides the debug/save/quit options.
     """
-    def __init__(self, shortTraceback=None, longTracebackFile=None, *args, **kwargs):
+    def __init__(self, shortTraceback=None, longTraceback=None, *args, **kwargs):
         """Create a new MainExceptionWindow instance.  This must handle
            creating the dialog and populating it with widgets, but must not
            run the dialog.  A self.dialog attribute should be created that
@@ -85,8 +85,8 @@ class AbstractMainExceptionWindow(object):
 
            shortTraceback    -- The short traceback (usually, just the stack
                                 trace).
-           longTracebackFile -- A file containing the output of
-                                ExceptionDump.write().
+           longTraceback     -- The long traceback (full traceback and the main
+                                object dump).
         """
         pass
 
diff --git a/meh/ui/gui.py b/meh/ui/gui.py
index 2b6ff15..035733f 100644
--- a/meh/ui/gui.py
+++ b/meh/ui/gui.py
@@ -70,8 +70,8 @@ class SaveExceptionWindow(AbstractSaveExceptionWindow):
         report.report(self.signature, self.io)
 
 class MainExceptionWindow(AbstractMainExceptionWindow):
-    def __init__(self, shortTraceback=None, longTracebackFile=None, *args, **kwargs):
-        AbstractMainExceptionWindow.__init__(self, shortTraceback, longTracebackFile,
+    def __init__(self, shortTraceback=None, longTraceback=None, *args, **kwargs):
+        AbstractMainExceptionWindow.__init__(self, shortTraceback, longTraceback,
                                              *args, **kwargs)
 
         builder = Gtk.Builder()
@@ -83,13 +83,7 @@ class MainExceptionWindow(AbstractMainExceptionWindow):
 
         self._traceback_buffer = builder.get_object("tracebackBuffer")
 
-        if longTracebackFile:
-            with open(longTracebackFile) as fobj:
-                long_traceback = ""
-                for line in fobj:
-                    long_traceback += line
-
-        self._traceback_buffer.set_text(long_traceback)
+        self._traceback_buffer.set_text(longTraceback)
         self._response = MAIN_RESPONSE_QUIT
 
     def destroy(self, *args, **kwargs):
diff --git a/meh/ui/text.py b/meh/ui/text.py
index 717212e..3cdde37 100644
--- a/meh/ui/text.py
+++ b/meh/ui/text.py
@@ -63,8 +63,8 @@ class SaveExceptionWindow(AbstractSaveExceptionWindow):
         report.report(self.signature, self.io)
 
 class MainExceptionWindow(AbstractMainExceptionWindow):
-    def __init__(self, shortTraceback=None, longTracebackFile=None, *args, **kwargs):
-        AbstractMainExceptionWindow.__init__(self, shortTraceback, longTracebackFile,
+    def __init__(self, shortTraceback=None, longTraceback=None, *args, **kwargs):
+        AbstractMainExceptionWindow.__init__(self, shortTraceback, longTraceback,
                                              *args, **kwargs)
 
         self.text = "%s\n\n" % shortTraceback
-- 
1.7.4.4



More information about the anaconda-patches mailing list