From 443ffddef35ed2dbdc1513b792ce3c5cc1341965 Mon Sep 17 00:00:00 2001 From: Eygene Ryabinkin Date: Mon, 28 Jan 2013 22:59:16 +0400 Subject: [PATCH 2/3] Use singleton depot for passing 'options' to our components Adding pseudo-items to the configuration (as we did for general.single-thread) isn't very good: user can define such option by himself and we will got very unexpected results. As we just needed to pass options.singlethreading to some of our components, we had wrapped the whole options to the singleton class that has read-only semantics. This way we can use this singleton from any piece of code and don't worry that options object will be modified in any way. Signed-off-by: Eygene Ryabinkin --- offlineimap/accounts.py | 3 ++- offlineimap/folder/Base.py | 3 ++- offlineimap/init.py | 5 ++--- offlineimap/utils/__init__.py | 22 ++++++++++++++++++++++ offlineimap/utils/depot.py | 36 ++++++++++++++++++++++++++++++++++++ setup.py | 3 ++- 6 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 offlineimap/utils/__init__.py create mode 100644 offlineimap/utils/depot.py diff --git a/offlineimap/accounts.py b/offlineimap/accounts.py index 88d62d8..e1d8de5 100644 --- a/offlineimap/accounts.py +++ b/offlineimap/accounts.py @@ -18,6 +18,7 @@ from offlineimap import mbnames, CustomConfig, OfflineImapError from offlineimap.repository import Repository from offlineimap.ui import getglobalui from offlineimap.threadutil import InstanceLimitedThread +from offlineimap.utils import depot from subprocess import Popen, PIPE from threading import Event import os @@ -321,7 +322,7 @@ class SyncableAccount(Account): self.ui.debug('', "Not syncing filtered folder '%s'" "[%s]" % (localfolder, localfolder.repository)) continue # Ignore filtered folder - if self.config.get('general', 'single-thread') == 'False': + if depot.Options().singlethreading == False: thread = InstanceLimitedThread(\ instancename = 'FOLDER_' + self.remoterepos.getname(), target = syncfolder, diff --git a/offlineimap/folder/Base.py b/offlineimap/folder/Base.py index e330086..a6feb78 100644 --- a/offlineimap/folder/Base.py +++ b/offlineimap/folder/Base.py @@ -19,6 +19,7 @@ from offlineimap import threadutil from offlineimap.ui import getglobalui from offlineimap.error import OfflineImapError import offlineimap.accounts +from offlineimap.utils import depot import os.path import re from sys import exc_info @@ -403,7 +404,7 @@ class BaseFolder(object): break self.ui.copyingmessage(uid, num+1, num_to_copy, self, dstfolder) # exceptions are caught in copymessageto() - if self.suggeststhreads() and self.config.get('general', 'single-thread') == 'False': + if self.suggeststhreads() and depot.Options().singlethreading == False: self.waitforthread() thread = threadutil.InstanceLimitedThread(\ self.getcopyinstancelimit(), diff --git a/offlineimap/init.py b/offlineimap/init.py index d25d7fa..4b0aced 100644 --- a/offlineimap/init.py +++ b/offlineimap/init.py @@ -29,6 +29,7 @@ from offlineimap.error import OfflineImapError from offlineimap.ui import UI_LIST, setglobalui, getglobalui from offlineimap.CustomConfig import CustomConfigParser from offlineimap.utils import stacktrace +from offlineimap.utils import depot class OfflineImap: @@ -161,6 +162,7 @@ class OfflineImap: ", ".join(UI_LIST.keys())) (options, args) = parser.parse_args() + depot.Options(options) #read in configuration file configfilename = os.path.expanduser(options.configfile) @@ -251,9 +253,6 @@ class OfflineImap: if type.lower() == 'imap': imaplib.Debug = 5 - # XXX: can we avoid introducing fake configuration item? - config.set_if_not_exists('general', 'single-thread', 'True' if options.singlethreading else 'False') - if options.runonce: # FIXME: maybe need a better for section in accounts.getaccountlist(config): diff --git a/offlineimap/utils/__init__.py b/offlineimap/utils/__init__.py new file mode 100644 index 0000000..3100ab9 --- /dev/null +++ b/offlineimap/utils/__init__.py @@ -0,0 +1,22 @@ +# Copyright 2013 Eygene A. Ryabinkin +# Various utility classes. + +import sys + +class Singleton(object): + def __new__(cls, *p, **k): + if not '_the_instance' in cls.__dict__: + cls._the_instance = super(Singleton, cls).__new__(cls) + return cls._the_instance + + def __init__(self): + """ + Returns True if this singleton was not ever initialized before + otherwise returns False. + + """ + if not '_inited' in self.__dict__: + self._inited = True + return True + else: + return False diff --git a/offlineimap/utils/depot.py b/offlineimap/utils/depot.py new file mode 100644 index 0000000..9d388f9 --- /dev/null +++ b/offlineimap/utils/depot.py @@ -0,0 +1,36 @@ +# Copyright 2013 Eygene A. Ryabinkin +# Implements global read-only instance +# that holds OfflineIMAP options. + +import offlineimap.utils + +class Options(offlineimap.utils.Singleton): + def __init__(self, options = None): + """ + Takes object like optparse.OptionParser.parse_args()[0] + and keeps it for reading configuration variables from it. + + Will initialize the object just once, at the first + instantiation. + + """ + first_init = offlineimap.utils.Singleton.__init__(self) + if options == None: + if first_init: + raise Exception ("Tried to use non-initialized option depot") + else: + return + else: + if first_init: + self.__options = options + else: + raise Exception ("Tried to initialize option depot twice") + + + def __getattr__(self, name): + """ + Returns value of the given option name. Raises AttributeError + if there is no option with such name. + + """ + return getattr(self.__options, name) diff --git a/setup.py b/setup.py index 27932eb..73db977 100644 --- a/setup.py +++ b/setup.py @@ -57,7 +57,8 @@ setup(name = "offlineimap", author_email = offlineimap.__author_email__, url = offlineimap.__homepage__, packages = ['offlineimap', 'offlineimap.folder', - 'offlineimap.repository', 'offlineimap.ui'], + 'offlineimap.repository', 'offlineimap.ui', + 'offlineimap.utils'], scripts = ['bin/offlineimap'], license = offlineimap.__copyright__ + \ ", Licensed under the GPL version 2", -- 1.8.1