From e119a70cec8c88fda205c157417f1d33106432d2 Mon Sep 17 00:00:00 2001 From: Romain Bignon Date: Thu, 1 Apr 2010 20:01:01 +0200 Subject: [PATCH] new system to load backends Now there is a single file ~/.weboob/backends, where every backends are instancied. There are two ways to create backends for frontends: - Use Weboob.load_backends(), to load every backends in the config file - Use Weboob.load_modules(), to instanciate every module one time --- weboob/backend.py | 37 +++++++++++++++++++++- weboob/backends/aum/backend.py | 1 + weboob/backends/canaltp/backend.py | 1 + weboob/backends/dlfp/backend.py | 4 +++ weboob/backends/dlfp/feeds.py | 2 +- weboob/backends/transilien/backend.py | 1 + weboob/frontends/dummy/scripts/dummy | 2 +- weboob/modules.py | 45 +++++++++++++++++++++++++-- weboob/ouiboube.py | 35 +++++++++------------ 9 files changed, 101 insertions(+), 27 deletions(-) diff --git a/weboob/backend.py b/weboob/backend.py index 8b691b91..4d3939cb 100644 --- a/weboob/backend.py +++ b/weboob/backend.py @@ -18,15 +18,50 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. """ +import re + class Backend: + # Module name. + NAME = None + # Name of the maintainer of this module. MAINTAINER = '' + # Email address of the maintainer. EMAIL = '' + # Version of module (for information only). VERSION = '' + # License of this module. LICENSE = '' + # Configuration required for this module. # Values must be ConfigField + # objects. + CONFIG = {} + + class ConfigField(object): + def __init__(self, default=None, is_masked=False, regexp=None, description=None): + self.default = default + self.is_masked = is_masked + self.regexp = regexp + self.description = description + + class ConfigError(Exception): pass def __init__(self, weboob, config): self.weboob = weboob - self.config = config + self.config = {} + for name, field in self.CONFIG.iteritems(): + value = config.get(name, field.default) + + if value is None: + raise Backend.ConfigError("Missing parameter '%s'" % name) + + if field.regexp and re.match(field.regexp, str(value)): + raise Backend.ConfigError("Value of '%s' does not match regexp '%s'" % (name, field.regexp)) + + if not field.default is None: + if isinstance(field.default, int): + value = int(value) + if isinstance(field.default, float): + value = float(value) + self.config[name] = value def has_caps(self, *caps): for c in caps: diff --git a/weboob/backends/aum/backend.py b/weboob/backends/aum/backend.py index f2d651ae..3a32993c 100644 --- a/weboob/backends/aum/backend.py +++ b/weboob/backends/aum/backend.py @@ -22,6 +22,7 @@ from weboob.backend import Backend from weboob.capabilities.messages import ICapMessages, ICapMessagesReply class AuMBackend(Backend, ICapMessages, ICapMessagesReply): + NAME = 'aum' MAINTAINER = 'Romain Bignon' EMAIL = 'romain@peerfuse.org' VERSION = '1.0' diff --git a/weboob/backends/canaltp/backend.py b/weboob/backends/canaltp/backend.py index 92c615ff..3bb7c781 100644 --- a/weboob/backends/canaltp/backend.py +++ b/weboob/backends/canaltp/backend.py @@ -24,6 +24,7 @@ from weboob.capabilities.travel import ICapTravel, Station, Departure from .browser import CanalTP class CanalTPBackend(Backend, ICapTravel): + NAME = 'canaltp' MAINTAINER = 'Romain Bignon' EMAIL = 'romain@peerfuse.org' VERSION = '1.0' diff --git a/weboob/backends/dlfp/backend.py b/weboob/backends/dlfp/backend.py index fcd16063..41f8b270 100644 --- a/weboob/backends/dlfp/backend.py +++ b/weboob/backends/dlfp/backend.py @@ -24,10 +24,14 @@ from weboob.capabilities.updatable import ICapUpdatable from feeds import ArticlesList class DLFPBackend(Backend, ICapMessages, ICapMessagesReply, ICapUpdatable): + NAME = 'dlfp' MAINTAINER = 'Romain Bignon' EMAIL = 'romain@peerfuse.org' VERSION = '1.0' LICENSE = 'GPLv3' + CONFIG = {'username': Backend.ConfigField(description='Username on website'), + 'password': Backend.ConfigField(description='Password of account', is_masked=True) + } def iter_messages(self): articles_list = ArticlesList('newspaper') diff --git a/weboob/backends/dlfp/feeds.py b/weboob/backends/dlfp/feeds.py index 6e0649b4..b602e3ba 100644 --- a/weboob/backends/dlfp/feeds.py +++ b/weboob/backends/dlfp/feeds.py @@ -21,7 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. from logging import warning import feedparser import re -import datetime +from datetime import datetime class Article: RSS = None diff --git a/weboob/backends/transilien/backend.py b/weboob/backends/transilien/backend.py index 38aac4be..0916d1ed 100644 --- a/weboob/backends/transilien/backend.py +++ b/weboob/backends/transilien/backend.py @@ -25,6 +25,7 @@ from .browser import Transilien from .stations import STATIONS class TransilienBackend(Backend, ICapTravel): + NAME = 'transilien' MAINTAINER = u'Julien Hébert' EMAIL = 'juke@free.fr' VERSION = '1.0' diff --git a/weboob/frontends/dummy/scripts/dummy b/weboob/frontends/dummy/scripts/dummy index f15ae854..9eaf8a0c 100755 --- a/weboob/frontends/dummy/scripts/dummy +++ b/weboob/frontends/dummy/scripts/dummy @@ -28,7 +28,7 @@ class Application(BaseApplication): APPNAME = 'dummy' def main(self, argv): - self.weboob.load_modules() + self.weboob.load_backends() for name, backend in self.weboob.iter_backends(): print '= Processing backend name = %s' % name diff --git a/weboob/modules.py b/weboob/modules.py index 2fbdddd1..fe821aea 100644 --- a/weboob/modules.py +++ b/weboob/modules.py @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import re import os +from ConfigParser import SafeConfigParser from logging import warning, debug from types import ClassType @@ -39,6 +40,9 @@ class Module: if not self.klass: raise ImportError("This is not a backend module (no Backend class found)") + def get_name(self): + return self.klass.NAME + def has_caps(self, *caps): for c in caps: if issubclass(self.klass, c): @@ -62,12 +66,47 @@ class ModulesLoader: def load_module(self, name): try: - backend = Module(name, __import__(name, fromlist=[name])) + module = Module(name, __import__(name, fromlist=[name])) except ImportError, e: warning('Unable to load module %s: %s' % (name, e)) return if name in self.modules: warning('Module "%s" is already loaded (%s)' % self.modules[name].module) return - self.modules[name] = backend - debug('Loaded module %s (%s)' % (name, backend.module.__name__)) + self.modules[module.get_name()] = module + debug('Loaded module %s (%s)' % (name, module.module.__name__)) + + def load_backends(self, confpath, caps, names): + config = SafeConfigParser() + config.read(confpath) + backends = {} + for name in config.sections(): + params = dict(config.items(name)) + try: + module = self.modules[params['_type']] + except KeyError: + warning('Unable to find module %s', name) + continue + + # Check conditions + if (not caps is None and not module.has_caps(caps)) or \ + (not names is None and not module.name in name): + continue + + try: + backends[name] = module.create_backend(self, params) + except Exception, e: + warning('Unable to load %s backend: %s' % (name, e)) + + return backends + + def load_modules_as_backends(self, caps, names): + backends = {} + for name, module in self.modules.iteritems(): + if (caps is None or module.has_caps(caps)) and \ + (names is None or module.name in names): + try: + backends[module.name] = module.create_backend(self, {}) + except Exception, e: + warning('Unable to load %s backend: %s' % (name, e)) + return backends diff --git a/weboob/ouiboube.py b/weboob/ouiboube.py index ee290ab9..03bd58ef 100644 --- a/weboob/ouiboube.py +++ b/weboob/ouiboube.py @@ -18,40 +18,33 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. """ +import os import sched import time from weboob.modules import ModulesLoader class Weboob: - def __init__(self, app_name): + WORKDIR = os.path.join(os.path.expanduser('~'), '.weboob') + BACKENDS_FILENAME = 'backends' + + def __init__(self, app_name, workdir=WORKDIR): self.app_name = app_name + self.workdir = workdir self.backends = {} self.scheduler = sched.scheduler(time.time, time.sleep) + self.modules_loader = ModulesLoader() self.modules_loader.load() - def load_modules(self, caps=None, name=None, backends=None): - if backends is None: - for name, module in self.modules_loader.modules.iteritems(): - if (not caps or module.has_caps(caps)) and \ - (not name or module.name == name): - backend = module.create_backend(self, None) - self.backends[module.name] = backend - else: - for key, backendcfg in backends.iteritems(): - try: - module = self.modules_loader[backendcfg.type] - except KeyError: - continue - if (caps and not module.has_caps(caps)) or \ - (name and module.name != name): - continue - self.backends[backendcfg.name] = module.create_backend(self, backendcfg) + def get_backends_filename(self): + return os.path.join(self.workdir, self.BACKENDS_FILENAME) - def load_module(self, modname, instname, backendcfg=None): - module = self.modules_loader[modname] - self.backends[instname] = module.create_backend(self, backendcfg) + def load_backends(self, caps=None, names=None): + self.backends.update(self.modules_loader.load_backends(self.get_backends_filename(), caps, names)) + + def load_modules(self, caps=None, names=None): + self.backends.update(self.modules_loader.load_modules_as_backends(caps, names)) def iter_backends(self, caps=None): for name, backend in self.backends.iteritems():