[PATCH 2/3] accounts.py: Use ui.error when raising exceptions

Sebastian Spaeth Sebastian at SSpaeth.de
Thu Aug 11 11:22:35 BST 2011


Rather than using ui.warn, use ui.error() which outputs Exceptions to
the error log, saving them to a stack, so we get notified again at the
end of the sync run.

Signed-off-by: Sebastian Spaeth <Sebastian at SSpaeth.de>
---
 Changelog.draft.rst        |    4 +
 offlineimap/accounts.py    |   23 ++++---
 offlineimap/folder/Base.py |  154 +++++++++++++++++++++++---------------------
 3 files changed, 98 insertions(+), 83 deletions(-)

diff --git a/Changelog.draft.rst b/Changelog.draft.rst
index e840717..53fb381 100644
--- a/Changelog.draft.rst
+++ b/Changelog.draft.rst
@@ -13,6 +13,10 @@ others.
 New Features
 ------------
 
+* When a message upload/download fails, we do not abort the whole folder
+  synchronization, but only skip that message, informing the user at the
+  end of the sync run.
+ 
 Changes
 -------
 
diff --git a/offlineimap/accounts.py b/offlineimap/accounts.py
index a989441..8653d48 100644
--- a/offlineimap/accounts.py
+++ b/offlineimap/accounts.py
@@ -22,6 +22,7 @@ from offlineimap.threadutil import InstanceLimitedThread
 from subprocess import Popen, PIPE
 from threading import Event
 import os
+from sys import exc_info
 import traceback
 
 def getaccountlist(customconfig):
@@ -178,16 +179,16 @@ class SyncableAccount(Account):
                 except (KeyboardInterrupt, SystemExit):
                     raise
                 except OfflineImapError, e:                    
-                    self.ui.warn(e.reason)
                     # Stop looping and bubble up Exception if needed.
                     if e.severity >= OfflineImapError.ERROR.REPO:
                         if looping:
                             looping -= 1
                         if e.severity >= OfflineImapError.ERROR.CRITICAL:
                             raise
-                except:
-                    self.ui.warn("Error occured attempting to sync account "\
-                                 "'%s':\n%s"% (self, traceback.format_exc()))
+                    self.ui.error(e, exc_info()[2])
+                except Exception, e:
+                    self.ui.error(e, msg = "While attempting to sync "
+                        "account %s:\n  %s"% (self, traceback.format_exc()))
                 else:
                     # after success sync, reset the looping counter to 3
                     if self.refreshperiod:
@@ -276,8 +277,10 @@ class SyncableAccount(Account):
             r = p.communicate()
             self.ui.callhook("Hook stdout: %s\nHook stderr:%s\n" % r)
             self.ui.callhook("Hook return code: %d" % p.returncode)
-        except:
-            self.ui.warn("Exception occured while calling hook")
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except Exception, e:
+            self.ui.error(e, exc_info()[2], msg = "Calling hook")
 
 
 def syncfolder(accountname, remoterepos, remotefolder, localrepos,
@@ -366,9 +369,9 @@ def syncfolder(accountname, remoterepos, remotefolder, localrepos,
         if e.severity > OfflineImapError.ERROR.FOLDER:
             raise
         else:
-            ui.warn("Aborting folder sync '%s' [acc: '%s']\nReason was: %s" %\
-                        (localfolder.name, accountname, e.reason))
-    except:
-        ui.warn("ERROR in syncfolder for %s folder %s: %s" % \
+            ui.error(e, exc_info()[2], msg = "Aborting folder sync '%s' "
+                     "[acc: '%s']" % (localfolder, accountname))
+    except Exception, e:
+        ui.error(e, msg = "ERROR in syncfolder for %s folder %s: %s" % \
                 (accountname,remotefolder.getvisiblename(),
                  traceback.format_exc()))
diff --git a/offlineimap/folder/Base.py b/offlineimap/folder/Base.py
index 0d5ddae..5a67775 100644
--- a/offlineimap/folder/Base.py
+++ b/offlineimap/folder/Base.py
@@ -19,6 +19,7 @@ from offlineimap import threadutil
 from offlineimap.ui import getglobalui
 import os.path
 import re
+from sys import exc_info
 import traceback
 
 class BaseFolder(object):
@@ -229,62 +230,55 @@ class BaseFolder(object):
         # synced to the status cache.  This is only a problem with
         # self.getmessage().  So, don't call self.getmessage unless
         # really needed.
-        try:
-            if register: # output that we start a new thread
-                self.ui.registerthread(self.getaccountname())
-
-            message = None
-            flags = self.getmessageflags(uid)
-            rtime = self.getmessagetime(uid)
-
-            if uid > 0 and dstfolder.uidexists(uid):
-                # dst has message with that UID already, only update status
-                statusfolder.savemessage(uid, None, flags, rtime)
-                return
-
-            self.ui.copyingmessage(uid, self, [dstfolder])
-            # If any of the destinations actually stores the message body,
-            # load it up.
-            if dstfolder.storesmessages():
-
-                message = self.getmessage(uid)
-            #Succeeded? -> IMAP actually assigned a UID. If newid
-            #remained negative, no server was willing to assign us an
-            #UID. If newid is 0, saving succeeded, but we could not
-            #retrieve the new UID. Ignore message in this case.
-            newuid = dstfolder.savemessage(uid, message, flags, rtime)
-            if newuid > 0:
-                if newuid != uid:
-                    # Got new UID, change the local uid.
-                    #TODO: Maildir could do this with a rename rather than
-                    #load/save/del operation, IMPLEMENT a changeuid()
-                    #function or so.
-                    self.savemessage(newuid, message, flags, rtime)
-                    self.deletemessage(uid)
-                    uid = newuid
-                # Save uploaded status in the statusfolder
-                statusfolder.savemessage(uid, message, flags, rtime)
-            elif newuid == 0:
-                # Message was stored to dstfolder, but we can't find it's UID
-                # This means we can't link current message to the one created
-                # in IMAP. So we just delete local message and on next run
-                # we'll sync it back
-                # XXX This could cause infinite loop on syncing between two
-                # IMAP servers ...
+        if register: # output that we start a new thread
+            self.ui.registerthread(self.getaccountname())
+
+        message = None
+        flags = self.getmessageflags(uid)
+        rtime = self.getmessagetime(uid)
+
+        if uid > 0 and dstfolder.uidexists(uid):
+            # dst has message with that UID already, only update status
+            statusfolder.savemessage(uid, None, flags, rtime)
+            return
+
+        self.ui.copyingmessage(uid, self, [dstfolder])
+        # If any of the destinations actually stores the message body,
+        # load it up.
+        if dstfolder.storesmessages():
+            message = self.getmessage(uid)
+        #Succeeded? -> IMAP actually assigned a UID. If newid
+        #remained negative, no server was willing to assign us an
+        #UID. If newid is 0, saving succeeded, but we could not
+        #retrieve the new UID. Ignore message in this case.
+        newuid = dstfolder.savemessage(uid, message, flags, rtime)
+        if newuid > 0:
+            if newuid != uid:
+                # Got new UID, change the local uid.
+                #TODO: Maildir could do this with a rename rather than
+                #load/save/del operation, IMPLEMENT a changeuid()
+                #function or so.
+                self.savemessage(newuid, message, flags, rtime)
                 self.deletemessage(uid)
-            else:
-                raise UserWarning("Trying to save msg (uid %d) on folder "
-                                  "%s returned invalid uid %d" % \
-                                      (uid,
-                                       dstfolder.getvisiblename(),
-                                       newuid))
-        except (KeyboardInterrupt):
-            raise
-        except:
-            self.ui.warn("ERROR attempting to copy message " + str(uid) \
-                 + " for account " + self.getaccountname() + ":" \
-                 + traceback.format_exc())
-            raise
+                uid = newuid
+            # Save uploaded status in the statusfolder
+            statusfolder.savemessage(uid, message, flags, rtime)
+
+        elif newuid == 0:
+            # Message was stored to dstfolder, but we can't find it's UID
+            # This means we can't link current message to the one created
+            # in IMAP. So we just delete local message and on next run
+            # we'll sync it back
+            # XXX This could cause infinite loop on syncing between two
+            # IMAP servers ...
+            self.deletemessage(uid)
+        else:
+            raise OfflineImapError("Trying to save msg (uid %d) on folder "
+                              "%s returned invalid uid %d" % \
+                                  (uid,
+                                   dstfolder.getvisiblename(),
+                                   newuid),
+                                   OfflineImapError.ERROR.MESSAGE)
 
     def syncmessagesto_copy(self, dstfolder, statusfolder):
         """Pass1: Copy locally existing messages not on the other side
@@ -303,20 +297,30 @@ class BaseFolder(object):
                               statusfolder.uidexists(uid),
                             self.getmessageuidlist())
         for uid in copylist:
-            if self.suggeststhreads():
-                self.waitforthread()
-                thread = threadutil.InstanceLimitedThread(\
-                    self.getcopyinstancelimit(),
-                    target = self.copymessageto,
-                    name = "Copy message %d from %s" % (uid,
+            try:
+                if self.suggeststhreads():
+                    self.waitforthread()
+                    thread = threadutil.InstanceLimitedThread(\
+                        self.getcopyinstancelimit(),
+                        target = self.copymessageto,
+                        name = "Copy message %d from %s" % (uid,
                                                         self.getvisiblename()),
-                    args = (uid, dstfolder, statusfolder))
-                thread.setDaemon(1)
-                thread.start()
-                threads.append(thread)
-            else:
-                self.copymessageto(uid, dstfolder, statusfolder, register = 0)
-
+                        args = (uid, dstfolder, statusfolder))
+                    thread.setDaemon(1)
+                    thread.start()
+                    threads.append(thread)
+                else:
+                    self.copymessageto(uid, dstfolder, statusfolder,
+                                       register = 0)
+            except OfflineImapError, e:
+                if e.severity > OfflineImapError.ERROR.Message:
+                    raise # buble severe errors up
+                self.ui.error(e, exc_info()[2])
+            except Exception, e:
+                self.ui.error(e, "Copying message %s [acc: %s]:\n %s" %\
+                                  (uid, self.getaccountname(),
+                                   traceback.format_exc()))
+                raise    #raise on unknown errors, so we can fix those
         for thread in threads:
             thread.join()
 
@@ -421,8 +425,12 @@ class BaseFolder(object):
                 action(dstfolder, statusfolder)
             except (KeyboardInterrupt):
                 raise
-            except:
-                self.ui.warn("ERROR attempting to sync flags " \
-                             + "for account " + self.getaccountname() \
-                             + ":" + traceback.format_exc())
-                raise
+            except OfflineImap, e:
+                if e.severity > OfflineImapError.ERROR.FOLDER:
+                    raise
+                self.ui.error(e, exc_info()[2])
+            except Exception, e:
+                self.ui.error(e, msg = "ERROR attempting to sync folder %s "
+                             "[acc: %s]:\n  %s" (self, self.getaccountname(),
+                                                 traceback.format_exc()))
+                raise # raise unknown Exceptions so we can fix them
-- 
1.7.4.1





More information about the OfflineIMAP-project mailing list