Reformat offlineimap/ui/UIBase.py

Add some spaces, remove lines,... now format is better (lintian).
This commit is contained in:
Rodolfo García Peñas (kix) 2020-08-29 19:59:05 +02:00
parent 6e0647de1a
commit ee236ec987

View File

@ -28,18 +28,21 @@ from collections import deque
import offlineimap import offlineimap
from offlineimap.error import OfflineImapError from offlineimap.error import OfflineImapError
debugtypes = {'':'Other offlineimap related sync messages', debugtypes = {'': 'Other offlineimap related sync messages',
'imap': 'IMAP protocol debugging', 'imap': 'IMAP protocol debugging',
'maildir': 'Maildir repository debugging', 'maildir': 'Maildir repository debugging',
'thread': 'Threading debugging'} 'thread': 'Threading debugging'}
globalui = None globalui = None
def setglobalui(newui): def setglobalui(newui):
"""Set the global ui object to be used for logging.""" """Set the global ui object to be used for logging."""
global globalui global globalui
globalui = newui globalui = newui
def getglobalui(): def getglobalui():
"""Return the current ui object.""" """Return the current ui object."""
@ -81,7 +84,7 @@ class UIBase(object):
# create console handler with a higher log level # create console handler with a higher log level
ch = logging.StreamHandler(sys.stdout) ch = logging.StreamHandler(sys.stdout)
#ch.setLevel(logging.DEBUG) # ch.setLevel(logging.DEBUG)
# create formatter and add it to the handlers # create formatter and add it to the handlers
self.formatter = logging.Formatter("%(message)s") self.formatter = logging.Formatter("%(message)s")
ch.setFormatter(self.formatter) ch.setFormatter(self.formatter)
@ -105,15 +108,15 @@ class UIBase(object):
"""Create file handler which logs to file.""" """Create file handler which logs to file."""
fh = logging.FileHandler(logfile, 'at') fh = logging.FileHandler(logfile, 'at')
#fh.setLevel(logging.DEBUG) # fh.setLevel(logging.DEBUG)
file_formatter = logging.Formatter("%(asctime)s %(levelname)s: " file_formatter = logging.Formatter("%(asctime)s %(levelname)s: "
"%(message)s", '%Y-%m-%d %H:%M:%S') "%(message)s", '%Y-%m-%d %H:%M:%S')
fh.setFormatter(file_formatter) fh.setFormatter(file_formatter)
self.logger.addHandler(fh) self.logger.addHandler(fh)
# write out more verbose initial info blurb on the log file # write out more verbose initial info blurb on the log file
p_ver = ".".join([str(x) for x in sys.version_info[0:3]]) p_ver = ".".join([str(x) for x in sys.version_info[0:3]])
msg = "OfflineImap %s starting...\n Python: %s Platform: %s\n "\ msg = "OfflineImap %s starting...\n Python: %s Platform: %s\n " \
"Args: %s"% (offlineimap.__version__, p_ver, sys.platform, "Args: %s" % (offlineimap.__version__, p_ver, sys.platform,
" ".join(sys.argv)) " ".join(sys.argv))
record = logging.LogRecord('OfflineImap', logging.INFO, __file__, record = logging.LogRecord('OfflineImap', logging.INFO, __file__,
None, msg, None, None) None, msg, None, None)
@ -158,9 +161,9 @@ class UIBase(object):
"repo %s") "repo %s")
""" """
if msg: if msg:
self.logger.error("ERROR: %s\n %s"% (msg, exc)) self.logger.error("ERROR: %s\n %s" % (msg, exc))
else: else:
self.logger.error("ERROR: %s"% (exc)) self.logger.error("ERROR: %s" % (exc))
instant_traceback = exc_traceback instant_traceback = exc_traceback
if not self.debuglist: if not self.debuglist:
@ -178,11 +181,11 @@ class UIBase(object):
if cur_thread in self.threadaccounts: if cur_thread in self.threadaccounts:
# was already associated with an old account, update info # was already associated with an old account, update info
self.debug('thread', "Register thread '%s' (previously '%s', now " self.debug('thread', "Register thread '%s' (previously '%s', now "
"'%s')"% (cur_thread.getName(), "'%s')" % (cur_thread.getName(),
self.getthreadaccount(cur_thread), account)) self.getthreadaccount(cur_thread), account))
else: else:
self.debug('thread', "Register new thread '%s' (account '%s')"% self.debug('thread', "Register new thread '%s' (account '%s')" %
(cur_thread.getName(), account)) (cur_thread.getName(), account))
self.threadaccounts[cur_thread] = account self.threadaccounts[cur_thread] = account
def unregisterthread(self, thr): def unregisterthread(self, thr):
@ -190,7 +193,7 @@ class UIBase(object):
if thr in self.threadaccounts: if thr in self.threadaccounts:
del self.threadaccounts[thr] del self.threadaccounts[thr]
self.debug('thread', "Unregister thread '%s'"% thr.getName()) self.debug('thread', "Unregister thread '%s'" % thr.getName())
def getthreadaccount(self, thr=None): def getthreadaccount(self, thr=None):
"""Get Account() for a thread (current if None) """Get Account() for a thread (current if None)
@ -216,7 +219,7 @@ class UIBase(object):
if len(self.debugmessages[cur_thread]) > self.debugmsglen: if len(self.debugmessages[cur_thread]) > self.debugmsglen:
self.debugmessages[cur_thread].popleft() self.debugmessages[cur_thread].popleft()
if debugtype in self.debuglist: # log if we are supposed to do so if debugtype in self.debuglist: # log if we are supposed to do so
self.logger.debug("[%s]: %s" % (debugtype, msg)) self.logger.debug("[%s]: %s" % (debugtype, msg))
def add_debug(self, debugtype): def add_debug(self, debugtype):
@ -254,50 +257,50 @@ class UIBase(object):
################################################## INPUT ################################################## INPUT
def getpass(self, username, config, errmsg = None): def getpass(self, username, config, errmsg=None):
raise NotImplementedError("Prompting for a password is not supported" raise NotImplementedError("Prompting for a password is not supported"
" in this UI backend.") " in this UI backend.")
def folderlist(self, folder_list): def folderlist(self, folder_list):
return ', '.join(["%s[%s]"% \ return ', '.join(["%s[%s]" % \
(self.getnicename(x), x.getname()) for x in folder_list]) (self.getnicename(x), x.getname()) for x in folder_list])
################################################## WARNINGS ################################################## WARNINGS
def msgtoreadonly(self, destfolder, uid, content, flags): def msgtoreadonly(self, destfolder, uid, content, flags):
if self.config.has_option('general', 'ignore-readonly') and \ if self.config.has_option('general', 'ignore-readonly') and \
self.config.getboolean('general', 'ignore-readonly'): self.config.getboolean('general', 'ignore-readonly'):
return return
self.warn("Attempted to synchronize message %d to folder %s[%s], " self.warn("Attempted to synchronize message %d to folder %s[%s], "
"but that folder is read-only. The message will not be " "but that folder is read-only. The message will not be "
"copied to that folder."% ( "copied to that folder." % (
uid, self.getnicename(destfolder), destfolder)) uid, self.getnicename(destfolder), destfolder))
def flagstoreadonly(self, destfolder, uidlist, flags): def flagstoreadonly(self, destfolder, uidlist, flags):
if self.config.has_option('general', 'ignore-readonly') and \ if self.config.has_option('general', 'ignore-readonly') and \
self.config.getboolean('general', 'ignore-readonly'): self.config.getboolean('general', 'ignore-readonly'):
return return
self.warn("Attempted to modify flags for messages %s in folder %s[%s], " self.warn("Attempted to modify flags for messages %s in folder %s[%s], "
"but that folder is read-only. No flags have been modified " "but that folder is read-only. No flags have been modified "
"for that message."% ( "for that message." % (
str(uidlist), self.getnicename(destfolder), destfolder)) str(uidlist), self.getnicename(destfolder), destfolder))
def labelstoreadonly(self, destfolder, uidlist, labels): def labelstoreadonly(self, destfolder, uidlist, labels):
if self.config.has_option('general', 'ignore-readonly') and \ if self.config.has_option('general', 'ignore-readonly') and \
self.config.getboolean('general', 'ignore-readonly'): self.config.getboolean('general', 'ignore-readonly'):
return return
self.warn("Attempted to modify labels for messages %s in folder %s[%s], " self.warn("Attempted to modify labels for messages %s in folder %s[%s], "
"but that folder is read-only. No labels have been modified " "but that folder is read-only. No labels have been modified "
"for that message."% ( "for that message." % (
str(uidlist), self.getnicename(destfolder), destfolder)) str(uidlist), self.getnicename(destfolder), destfolder))
def deletereadonly(self, destfolder, uidlist): def deletereadonly(self, destfolder, uidlist):
if self.config.has_option('general', 'ignore-readonly') and \ if self.config.has_option('general', 'ignore-readonly') and \
self.config.getboolean('general', 'ignore-readonly'): self.config.getboolean('general', 'ignore-readonly'):
return return
self.warn("Attempted to delete messages %s in folder %s[%s], but that " self.warn("Attempted to delete messages %s in folder %s[%s], but that "
"folder is read-only. No messages have been deleted in that " "folder is read-only. No messages have been deleted in that "
"folder."% (str(uidlist), self.getnicename(destfolder), "folder." % (str(uidlist), self.getnicename(destfolder),
destfolder)) destfolder))
################################################## MESSAGES ################################################## MESSAGES
@ -314,32 +317,32 @@ class UIBase(object):
if not self.logger.isEnabledFor(logging.INFO): return if not self.logger.isEnabledFor(logging.INFO): return
displaystr = '' displaystr = ''
hostname = hostname if hostname else '' hostname = hostname if hostname else ''
port = "%s"% port if port else '' port = "%s" % port if port else ''
if hostname: if hostname:
displaystr = ' to %s:%s' % (hostname, port) displaystr = ' to %s:%s' % (hostname, port)
self.logger.info("Establishing connection%s (%s)"% self.logger.info("Establishing connection%s (%s)" %
(displaystr, reposname)) (displaystr, reposname))
def acct(self, account): def acct(self, account):
"""Output that we start syncing an account (and start counting).""" """Output that we start syncing an account (and start counting)."""
self.acct_startimes[account] = time.time() self.acct_startimes[account] = time.time()
self.logger.info("*** Processing account %s"% account) self.logger.info("*** Processing account %s" % account)
def acctdone(self, account): def acctdone(self, account):
"""Output that we finished syncing an account (in which time).""" """Output that we finished syncing an account (in which time)."""
sec = time.time() - self.acct_startimes[account] sec = time.time() - self.acct_startimes[account]
del self.acct_startimes[account] del self.acct_startimes[account]
self.logger.info("*** Finished account '%s' in %d:%02d"% self.logger.info("*** Finished account '%s' in %d:%02d" %
(account, sec // 60, sec % 60)) (account, sec // 60, sec % 60))
def syncfolders(self, src_repo, dst_repo): def syncfolders(self, src_repo, dst_repo):
"""Log 'Copying folder structure...'.""" """Log 'Copying folder structure...'."""
if self.logger.isEnabledFor(logging.DEBUG): if self.logger.isEnabledFor(logging.DEBUG):
self.debug('', "Copying folder structure from %s to %s" %\ self.debug('', "Copying folder structure from %s to %s" % \
(src_repo, dst_repo)) (src_repo, dst_repo))
############################## Folder syncing ############################## Folder syncing
def makefolder(self, repo, foldername): def makefolder(self, repo, foldername):
@ -352,9 +355,9 @@ class UIBase(object):
def syncingfolder(self, srcrepos, srcfolder, destrepos, destfolder): def syncingfolder(self, srcrepos, srcfolder, destrepos, destfolder):
"""Called when a folder sync operation is started.""" """Called when a folder sync operation is started."""
self.logger.info("Syncing %s: %s -> %s"% (srcfolder, self.logger.info("Syncing %s: %s -> %s" % (srcfolder,
self.getnicename(srcrepos), self.getnicename(srcrepos),
self.getnicename(destrepos))) self.getnicename(destrepos)))
def skippingfolder(self, folder): def skippingfolder(self, folder):
"""Called when a folder sync operation is started.""" """Called when a folder sync operation is started."""
@ -364,38 +367,38 @@ class UIBase(object):
self.uidval_problem = True self.uidval_problem = True
self.logger.warning("UID validity problem for folder %s (repo %s) " self.logger.warning("UID validity problem for folder %s (repo %s) "
"(saved %d; got %d); skipping it. Please see FAQ " "(saved %d; got %d); skipping it. Please see FAQ "
"and manual on how to handle this."% \ "and manual on how to handle this." % \
(folder, folder.getrepository(), (folder, folder.getrepository(),
folder.get_saveduidvalidity(), folder.get_uidvalidity())) folder.get_saveduidvalidity(), folder.get_uidvalidity()))
def loadmessagelist(self, repos, folder): def loadmessagelist(self, repos, folder):
self.logger.debug("Loading message list for %s[%s]"% ( self.logger.debug("Loading message list for %s[%s]" % (
self.getnicename(repos), self.getnicename(repos),
folder)) folder))
def messagelistloaded(self, repos, folder, count): def messagelistloaded(self, repos, folder, count):
self.logger.debug("Message list for %s[%s] loaded: %d messages" % ( self.logger.debug("Message list for %s[%s] loaded: %d messages" % (
self.getnicename(repos), folder, count)) self.getnicename(repos), folder, count))
############################## Message syncing ############################## Message syncing
def syncingmessages(self, sr, srcfolder, dr, dstfolder): def syncingmessages(self, sr, srcfolder, dr, dstfolder):
self.logger.debug("Syncing messages %s[%s] -> %s[%s]" % ( self.logger.debug("Syncing messages %s[%s] -> %s[%s]" % (
self.getnicename(sr), srcfolder, self.getnicename(sr), srcfolder,
self.getnicename(dr), dstfolder)) self.getnicename(dr), dstfolder))
def ignorecopyingmessage(self, uid, src, destfolder): def ignorecopyingmessage(self, uid, src, destfolder):
"""Output a log line stating which message is ignored.""" """Output a log line stating which message is ignored."""
self.logger.info("IGNORED: Copy message UID %s %s:%s -> %s"% ( self.logger.info("IGNORED: Copy message UID %s %s:%s -> %s" % (
uid, src.repository, src, destfolder.repository)) uid, src.repository, src, destfolder.repository))
def copyingmessage(self, uid, num, num_to_copy, src, destfolder): def copyingmessage(self, uid, num, num_to_copy, src, destfolder):
"""Output a log line stating which message we copy.""" """Output a log line stating which message we copy."""
self.logger.info("Copy message UID %s (%d/%d) %s:%s -> %s:%s"% ( self.logger.info("Copy message UID %s (%d/%d) %s:%s -> %s:%s" % (
uid, num, num_to_copy, src.repository, src, uid, num, num_to_copy, src.repository, src,
destfolder.repository, destfolder)) destfolder.repository, destfolder))
def deletingmessages(self, uidlist, destlist): def deletingmessages(self, uidlist, destlist):
ds = self.folderlist(destlist) ds = self.folderlist(destlist)
@ -406,41 +409,41 @@ class UIBase(object):
def addingflags(self, uidlist, flags, dest): def addingflags(self, uidlist, flags, dest):
self.logger.info("Adding flag %s to %d messages on %s" % ( self.logger.info("Adding flag %s to %d messages on %s" % (
", ".join(flags), len(uidlist), dest)) ", ".join(flags), len(uidlist), dest))
def deletingflags(self, uidlist, flags, dest): def deletingflags(self, uidlist, flags, dest):
self.logger.info("Deleting flag %s from %d messages on %s" % ( self.logger.info("Deleting flag %s from %d messages on %s" % (
", ".join(flags), len(uidlist), dest)) ", ".join(flags), len(uidlist), dest))
def addinglabels(self, uidlist, label, dest): def addinglabels(self, uidlist, label, dest):
self.logger.info("Adding label %s to %d messages on %s" % ( self.logger.info("Adding label %s to %d messages on %s" % (
label, len(uidlist), dest)) label, len(uidlist), dest))
def deletinglabels(self, uidlist, label, dest): def deletinglabels(self, uidlist, label, dest):
self.logger.info("Deleting label %s from %d messages on %s" % ( self.logger.info("Deleting label %s from %d messages on %s" % (
label, len(uidlist), dest)) label, len(uidlist), dest))
def settinglabels(self, uid, num, num_to_set, labels, dest): def settinglabels(self, uid, num, num_to_set, labels, dest):
self.logger.info("Setting labels to message %d on %s (%d of %d): %s" % ( self.logger.info("Setting labels to message %d on %s (%d of %d): %s" % (
uid, dest, num, num_to_set, ", ".join(labels))) uid, dest, num, num_to_set, ", ".join(labels)))
def collectingdata(self, uidlist, source): def collectingdata(self, uidlist, source):
if uidlist: if uidlist:
self.logger.info("Collecting data from %d messages on %s"% ( self.logger.info("Collecting data from %d messages on %s" % (
len(uidlist), source)) len(uidlist), source))
else: else:
self.logger.info("Collecting data from messages on %s"% source) self.logger.info("Collecting data from messages on %s" % source)
def serverdiagnostics(self, repository, type): def serverdiagnostics(self, repository, type):
"""Connect to repository and output useful information for debugging.""" """Connect to repository and output useful information for debugging."""
conn = None conn = None
self._msg("%s repository '%s': type '%s'" % (type, repository.name, self._msg("%s repository '%s': type '%s'" % (type, repository.name,
self.getnicename(repository))) self.getnicename(repository)))
try: try:
if hasattr(repository, 'gethost'): # IMAP if hasattr(repository, 'gethost'): # IMAP
self._msg("Host: %s Port: %s SSL: %s"% (repository.gethost(), self._msg("Host: %s Port: %s SSL: %s" % (repository.gethost(),
repository.getport(), repository.getssl())) repository.getport(), repository.getssl()))
try: try:
conn = repository.imapserver.acquireconnection() conn = repository.imapserver.acquireconnection()
except OfflineImapError as e: except OfflineImapError as e:
@ -448,11 +451,11 @@ class UIBase(object):
else: else:
if 'ID' in conn.capabilities: if 'ID' in conn.capabilities:
self._msg("Server supports ID extension.") self._msg("Server supports ID extension.")
#TODO: Debug and make below working, it hangs Gmail # TODO: Debug and make below working, it hangs Gmail
#res_type, response = conn.id(( # res_type, response = conn.id((
# 'name', offlineimap.__productname__, # 'name', offlineimap.__productname__,
# 'version', offlineimap.__version__)) # 'version', offlineimap.__version__))
#self._msg("Server ID: %s %s" % (res_type, response[0])) # self._msg("Server ID: %s %s" % (res_type, response[0]))
self._msg("Server welcome string: %s" % str(conn.welcome)) self._msg("Server welcome string: %s" % str(conn.welcome))
self._msg("Server capabilities: %s\n" % str(conn.capabilities)) self._msg("Server capabilities: %s\n" % str(conn.capabilities))
repository.imapserver.releaseconnection(conn) repository.imapserver.releaseconnection(conn)
@ -469,35 +472,37 @@ class UIBase(object):
folders = repository.getfolders() folders = repository.getfolders()
foldernames = [(f.name, f.getvisiblename(), f.sync_this) foldernames = [(f.name, f.getvisiblename(), f.sync_this)
for f in folders] for f in folders]
folders = [] folders = []
for name, visiblename, sync_this in foldernames: for name, visiblename, sync_this in foldernames:
syncstr = "" if sync_this else " (disabled)" syncstr = "" if sync_this else " (disabled)"
if name == visiblename: folders.append("%s%s" % (name, if name == visiblename:
syncstr)) folders.append("%s%s" % (name,
else: folders.append("%s -> %s%s" % (name, syncstr))
else:
folders.append("%s -> %s%s" % (name,
visiblename, syncstr)) visiblename, syncstr))
self._msg("Folderlist:\n %s\n" % "\n ".join(folders)) self._msg("Folderlist:\n %s\n" % "\n ".join(folders))
finally: finally:
if conn: #release any existing IMAP connection if conn: # release any existing IMAP connection
repository.imapserver.close() repository.imapserver.close()
def savemessage(self, debugtype, uid, flags, folder): def savemessage(self, debugtype, uid, flags, folder):
"""Output a log line stating that we save a msg.""" """Output a log line stating that we save a msg."""
self.debug(debugtype, "Write mail '%s:%d' with flags %s"% self.debug(debugtype, "Write mail '%s:%d' with flags %s" %
(folder, uid, repr(flags))) (folder, uid, repr(flags)))
################################################## Threads ################################################## Threads
def getThreadDebugLog(self, thread): def getThreadDebugLog(self, thread):
if thread in self.debugmessages: if thread in self.debugmessages:
message = "\nLast %d debug messages logged for %s prior to exception:\n"\ message = "\nLast %d debug messages logged for %s prior to exception:\n" \
% (len(self.debugmessages[thread]), thread.getName()) % (len(self.debugmessages[thread]), thread.getName())
message += "\n".join(self.debugmessages[thread]) message += "\n".join(self.debugmessages[thread])
else: else:
message = "\nNo debug messages were logged for %s."% \ message = "\nNo debug messages were logged for %s." % \
thread.getName() thread.getName()
return message return message
def delThreadDebugLog(self, thread): def delThreadDebugLog(self, thread):
@ -505,8 +510,8 @@ class UIBase(object):
del self.debugmessages[thread] del self.debugmessages[thread]
def getThreadExceptionString(self, thread): def getThreadExceptionString(self, thread):
message = "Thread '%s' terminated with exception:\n%s"% \ message = "Thread '%s' terminated with exception:\n%s" % \
(thread.getName(), thread.exit_stacktrace) (thread.getName(), thread.exit_stacktrace)
message += "\n" + self.getThreadDebugLog(thread) message += "\n" + self.getThreadDebugLog(thread)
return message return message
@ -518,28 +523,28 @@ class UIBase(object):
self.delThreadDebugLog(thread) self.delThreadDebugLog(thread)
self.terminate(100) self.terminate(100)
def terminate(self, exitstatus = 0, errortitle = None, errormsg = None): def terminate(self, exitstatus=0, errortitle=None, errormsg=None):
"""Called to terminate the application.""" """Called to terminate the application."""
#print any exceptions that have occurred over the run # print any exceptions that have occurred over the run
if not self.exc_queue.empty(): if not self.exc_queue.empty():
self.warn("ERROR: Exceptions occurred during the run!") self.warn("ERROR: Exceptions occurred during the run!")
if exitstatus == 0: if exitstatus == 0:
exitstatus = 1 exitstatus = 1
while not self.exc_queue.empty(): while not self.exc_queue.empty():
msg, exc, exc_traceback = self.exc_queue.get() msg, exc, exc_traceback = self.exc_queue.get()
if msg: if msg:
self.warn("ERROR: %s\n %s"% (msg, exc)) self.warn("ERROR: %s\n %s" % (msg, exc))
else: else:
self.warn("ERROR: %s"% (exc)) self.warn("ERROR: %s" % (exc))
if exc_traceback: if exc_traceback:
self.warn("\nTraceback:\n%s"% "".join( self.warn("\nTraceback:\n%s" % "".join(
traceback.format_tb(exc_traceback))) traceback.format_tb(exc_traceback)))
if errormsg and errortitle: if errormsg and errortitle:
self.warn('ERROR: %s\n\n%s\n'% (errortitle, errormsg)) self.warn('ERROR: %s\n\n%s\n' % (errortitle, errormsg))
elif errormsg: elif errormsg:
self.warn('%s\n'% errormsg) self.warn('%s\n' % errormsg)
if self.uidval_problem: if self.uidval_problem:
self.warn('At least one folder skipped due to UID validity problem') self.warn('At least one folder skipped due to UID validity problem')
if exitstatus == 0: if exitstatus == 0:
@ -595,8 +600,8 @@ class UIBase(object):
""" """
if sleepsecs > 0: if sleepsecs > 0:
if remainingsecs//60 != (remainingsecs-sleepsecs)//60: if remainingsecs // 60 != (remainingsecs - sleepsecs) // 60:
self.logger.debug("Next refresh in %.1f minutes" % ( self.logger.debug("Next refresh in %.1f minutes" % (
remainingsecs/60.0)) remainingsecs / 60.0))
time.sleep(sleepsecs) time.sleep(sleepsecs)
return 0 return 0