[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