diff --git a/weboob/applications/boobank/boobank.py b/weboob/applications/boobank/boobank.py index db36d232c5081302e259f1b0a88cb929e062261d..47393baf6937b0539304066112c7ed522b113718 100644 --- a/weboob/applications/boobank/boobank.py +++ b/weboob/applications/boobank/boobank.py @@ -35,7 +35,7 @@ class Boobank(ConsoleApplication): COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' def main(self, argv): - self.load_backends(ICapBank) + self.load_configured_backends(ICapBank) return self.process_command(*argv[1:]) @ConsoleApplication.command('List every available accounts') diff --git a/weboob/applications/chatoob/chatoob.py b/weboob/applications/chatoob/chatoob.py index a110a12af2948f17a575e0b03393e44064c7fa96..f3af85273d37864d2f9004ea7dd55d0a85fa64f1 100644 --- a/weboob/applications/chatoob/chatoob.py +++ b/weboob/applications/chatoob/chatoob.py @@ -32,7 +32,7 @@ class Chatoob(ConsoleApplication): COPYRIGHT = 'Copyright(C) 2010 Christophe Benz' def main(self, argv): - self.load_backends(ICapChat) + self.load_configured_backends(ICapChat) #for backend, result in self.weboob.do('start_chat_polling', self.on_new_chat_message): #logging.info(u'Polling chat messages for backend %s' % backend) return self.process_command(*argv[1:]) diff --git a/weboob/applications/havesex/havesex.py b/weboob/applications/havesex/havesex.py index 2a6dad156659aad78c0d943c5eba31f3791b0e87..4c510d705e937b802c3912c189e2052ce4b7cddd 100644 --- a/weboob/applications/havesex/havesex.py +++ b/weboob/applications/havesex/havesex.py @@ -38,7 +38,7 @@ class HaveSex(PromptApplication): def main(self, argv): self.load_config() - self.load_backends(ICapDating, storage=self.create_storage(self.STORAGE_FILENAME)) + self.load_configured_backends(ICapDating, storage=self.create_storage(self.STORAGE_FILENAME)) self.weboob.do('init_optimizations').wait() diff --git a/weboob/applications/masstransit/masstransit.py b/weboob/applications/masstransit/masstransit.py index bfd72b6ead3c2922cd464fbad7f273ead7f1f50f..05a5f34a55e16cf219f989a7f5f4116fb834f3e7 100644 --- a/weboob/applications/masstransit/masstransit.py +++ b/weboob/applications/masstransit/masstransit.py @@ -233,7 +233,6 @@ class Masstransit(BaseApplication): COPYRIGHT = 'Copyright(C) 2010 Julien Hébert' def main(self, argv): - "main fonction" - self.load_modules(ICapTravel) + self.load_backends(ICapTravel) MasstransitHildon(self.weboob) gtk.main() diff --git a/weboob/applications/monboob/monboob.py b/weboob/applications/monboob/monboob.py index 3876ec6fc5a446b66f1195a202d8f89a4ada8cc0..4786f8c32462b69a0cdf34868c1b97699e76e3a1 100644 --- a/weboob/applications/monboob/monboob.py +++ b/weboob/applications/monboob/monboob.py @@ -93,7 +93,7 @@ def create_weboob(self): def main(self, argv): self.load_config() - self.load_backends(ICapMessages, storage=self.create_storage()) + self.load_configured_backends(ICapMessages, storage=self.create_storage()) return self.process_command(*argv[1:]) diff --git a/weboob/applications/qboobmsg/main_window.py b/weboob/applications/qboobmsg/main_window.py index 8b7d56af0d5a2b75fd969705aa947c4c6d11bbfd..9eeee2c4fd731fd50c19faeb8c8ae4ccc8466d7b 100644 --- a/weboob/applications/qboobmsg/main_window.py +++ b/weboob/applications/qboobmsg/main_window.py @@ -36,10 +36,10 @@ def __init__(self, config, weboob, parent=None): self.setCentralWidget(self.manager) - self.connect(self.ui.actionModules, SIGNAL("triggered()"), self.modulesConfig) + self.connect(self.ui.actionBackends, SIGNAL("triggered()"), self.backendsConfig) self.connect(self.ui.actionRefresh, SIGNAL("triggered()"), self.refresh) - def modulesConfig(self): + def backendsConfig(self): bckndcfg = BackendCfg(self.weboob, (ICapMessages,), self) bckndcfg.show() diff --git a/weboob/applications/qboobmsg/qboobmsg.py b/weboob/applications/qboobmsg/qboobmsg.py index 732f29a110516236c425c89e381ab9db11071afe..0c0510e2b138905d17536d358fc8e33f46053dd2 100644 --- a/weboob/applications/qboobmsg/qboobmsg.py +++ b/weboob/applications/qboobmsg/qboobmsg.py @@ -27,7 +27,7 @@ class QBoobMsg(QtApplication): COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' def main(self, argv): - self.load_backends(ICapMessages, storage=self.create_storage()) + self.load_configured_backends(ICapMessages, storage=self.create_storage()) self.main_window = MainWindow(self.config, self.weboob) self.main_window.show() diff --git a/weboob/applications/qboobmsg/ui/main_window.ui b/weboob/applications/qboobmsg/ui/main_window.ui index 330e9460dcfd557badbec1203dc3ae5a688b4b44..f40742b6d79c77973a087526d68282498e94d337 100644 --- a/weboob/applications/qboobmsg/ui/main_window.ui +++ b/weboob/applications/qboobmsg/ui/main_window.ui @@ -29,7 +29,7 @@ File - + @@ -47,12 +47,12 @@ false - + - + - Modules + Backends diff --git a/weboob/applications/qhavesex/main_window.py b/weboob/applications/qhavesex/main_window.py index 276d694808627e982a43f9d0680633766899feb5..db595c93df96d1f8a8561872f8a4ab2481ff22f0 100644 --- a/weboob/applications/qhavesex/main_window.py +++ b/weboob/applications/qhavesex/main_window.py @@ -44,10 +44,10 @@ def __init__(self, config, weboob, parent=None): self.ui.tabWidget.addTab(ContactsWidget(self.weboob), self.tr('Contacts')) self.ui.tabWidget.addTab(QWidget(), self.tr('Calendar')) - self.connect(self.ui.actionModules, SIGNAL("triggered()"), self.modulesConfig) + self.connect(self.ui.actionBackends, SIGNAL("triggered()"), self.backendsConfig) self.connect(self.ui.tabWidget, SIGNAL('currentChanged(int)'), self.tabChanged) - def modulesConfig(self): + def backendsConfig(self): bckndcfg = BackendCfg(self.weboob, (ICapDating,), self) bckndcfg.show() diff --git a/weboob/applications/qhavesex/qhavesex.py b/weboob/applications/qhavesex/qhavesex.py index c2c127a41515c3402bf3bb1f5f8c5de012c6e420..efcafbefe86edfa84da727d46f5829fdb2952a51 100644 --- a/weboob/applications/qhavesex/qhavesex.py +++ b/weboob/applications/qhavesex/qhavesex.py @@ -28,7 +28,7 @@ class QHaveSex(QtApplication): STORAGE_FILENAME = 'dating.storage' def main(self, argv): - self.load_backends(ICapDating, storage=self.create_storage()) + self.load_configured_backends(ICapDating, storage=self.create_storage()) self.main_window = MainWindow(self.config, self.weboob) self.main_window.show() diff --git a/weboob/applications/qhavesex/ui/main_window.ui b/weboob/applications/qhavesex/ui/main_window.ui index 6a2b3e4774f600e3619d128279c331884e6c85fd..a04160d416d188b389b7ad38b85396c258395298 100644 --- a/weboob/applications/qhavesex/ui/main_window.ui +++ b/weboob/applications/qhavesex/ui/main_window.ui @@ -37,7 +37,7 @@ File - + @@ -54,11 +54,11 @@ false - + - + - Modules + Backends diff --git a/weboob/applications/qvideoob/qvideoob.py b/weboob/applications/qvideoob/qvideoob.py index 0fae8313900206f5c304b032184bb943849c3d6d..0362875941475775576dde5372cf4437866c7cf4 100644 --- a/weboob/applications/qvideoob/qvideoob.py +++ b/weboob/applications/qvideoob/qvideoob.py @@ -32,7 +32,7 @@ class QVideoob(QtApplication): } } def main(self, argv): - self.load_modules(ICapVideo) + self.load_backends(ICapVideo) self.load_config() self.main_window = MainWindow(self.config, self.weboob) diff --git a/weboob/applications/qweboobcfg/qweboobcfg.py b/weboob/applications/qweboobcfg/qweboobcfg.py index d269dbf1f55244349c181b1e8af723c3ce83b6ef..7c8f4925959c19608f5878c5ee8458e81c678133 100644 --- a/weboob/applications/qweboobcfg/qweboobcfg.py +++ b/weboob/applications/qweboobcfg/qweboobcfg.py @@ -27,7 +27,7 @@ class QWeboobCfg(QtApplication): COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' def main(self, argv): - self.load_backends() + self.load_configured_backends() self.dlg = BackendCfg(self.weboob) self.dlg.show() diff --git a/weboob/applications/travel/application.py b/weboob/applications/travel/application.py index 1172fb192fcc1e143495a9afa924f918b5dd209c..ca66ab3b0aed389c3945d78b9bd04e9cdee97efc 100644 --- a/weboob/applications/travel/application.py +++ b/weboob/applications/travel/application.py @@ -29,8 +29,7 @@ class Travel(ConsoleApplication): COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' def main(self, argv): - self.load_modules(ICapTravel) - + self.load_backends(ICapTravel) return self.process_command(*argv[1:]) @ConsoleApplication.command('Search stations') diff --git a/weboob/applications/videoob/videoob.py b/weboob/applications/videoob/videoob.py index 20cd1c3d2abdebf1e226a955e8e4879b275aa9bf..38aa231ffe266f10e62de2ae3b386411fd95c319 100644 --- a/weboob/applications/videoob/videoob.py +++ b/weboob/applications/videoob/videoob.py @@ -41,7 +41,7 @@ def main(self, argv): def command_info(self, _id): _id, backend_name = self.parse_id(_id) names = (backend_name,) if backend_name is not None else None - self.load_modules(ICapVideo, names=names) + self.load_backends(ICapVideo, names=names) for backend, video in self.weboob.do('get_video', _id): if video is None: continue @@ -49,7 +49,7 @@ def command_info(self, _id): @ConsoleApplication.command('Search for videos') def command_search(self, pattern=None): - self.load_modules(ICapVideo) + self.load_backends(ICapVideo) self.set_formatter_header(u'Search pattern: %s' % pattern if pattern else u'Last videos') for backend, video in self.do('iter_search_results', pattern=pattern, nsfw=self.options.nsfw): self.format(video, backend.name) diff --git a/weboob/applications/videoob_web/videoob_web.py b/weboob/applications/videoob_web/videoob_web.py index d40a5aee60853454c2b24f90133308f433a6b338..6466955c26f047a21b504e78881a69b3d270f6c2 100644 --- a/weboob/applications/videoob_web/videoob_web.py +++ b/weboob/applications/videoob_web/videoob_web.py @@ -72,7 +72,7 @@ def make_app(self, req): def main(self, argv): self.load_config() - self.weboob.load_modules(ICapVideo) + self.weboob.load_backends(ICapVideo) print 'Web server created. Listening on http://%s:%s' % ( self.config.get('host'), int(self.config.get('port'))) srv = make_server(self.config.get('host'), int(self.config.get('port')), self.make_app) diff --git a/weboob/applications/weboobcfg/weboobcfg.py b/weboob/applications/weboobcfg/weboobcfg.py index f49cef1a713ffaa2c87a9788bb3fa9b5e649ea74..117c317dc0da219f9c918b29836ffa7522d54796 100644 --- a/weboob/applications/weboobcfg/weboobcfg.py +++ b/weboob/applications/weboobcfg/weboobcfg.py @@ -44,65 +44,10 @@ def caps_included(self, modcaps, caps): return False return True - @ConsoleApplication.command('List backends') - def command_backends(self, *caps): - self.set_default_formatter('table') - self.weboob.modules_loader.load() - for name, backend in self.weboob.modules_loader.modules.iteritems(): - if caps and not self.caps_included(backend.iter_caps(), caps): - continue - row = OrderedDict([('Name', name), - ('Capabilities', ', '.join(cap.__name__ for cap in backend.iter_caps())), - ('Description', backend.get_description()), - ]) - self.format(row) - - @ConsoleApplication.command('List applications') - def command_applications(self, *caps): - applications = set() - import weboob.applications - for path in weboob.applications.__path__: - regexp = re.compile('^%s/([\w\d_]+)$' % path) - for root, dirs, files in os.walk(path): - m = regexp.match(root) - if m and '__init__.py' in files: - applications.add(m.group(1)) - print ' '.join(sorted(applications)).encode('utf-8') - - @ConsoleApplication.command('Display information about a backend') - def command_info(self, name): - try: - backend = self.weboob.modules_loader.get_or_load_module(name) - except KeyError: - logging.error('No such backend: "%s"' % name) - return 1 - - print '.------------------------------------------------------------------------------.' - print '| Backend %-68s |' % backend.get_name() - print "+-----------------.------------------------------------------------------------'" - print '| Version | %s' % backend.get_version() - print '| Maintainer | %s' % backend.get_maintainer() - print '| License | %s' % backend.get_license() - print '| Description | %s' % backend.get_description() - print '| Capabilities | %s' % ', '.join([cap.__name__ for cap in backend.iter_caps()]) - first = True - for key, field in backend.get_config().iteritems(): - value = field.description - if not field.default is None: - value += ' (default: %s)' % field.default - if first: - print '| | ' - print '| Configuration | %s: %s' % (key, value) - first = False - else: - print '| | %s: %s' % (key, value) - print "'-----------------'" - - @ConsoleApplication.command('Add a configured backend') def command_add(self, name, *options): - self.weboob.modules_loader.load() - if name not in [module_name for module_name, module in self.weboob.modules_loader.modules.iteritems()]: + self.weboob.backends_loader.load_all() + if name not in [name for name, backend in self.weboob.backends_loader.loaded.iteritems()]: logging.error(u'Backend "%s" does not exist.' % name) return 1 @@ -116,9 +61,9 @@ def command_add(self, name, *options): return 1 params[key] = value # ask for params non-specified on command-line arguments - module = self.weboob.modules_loader.get_or_load_module(name) + backend = self.weboob.backends_loader.get_or_load_backend(name) asked_config = False - for key, value in module.get_config().iteritems(): + for key, value in backend.config.iteritems(): if not asked_config: asked_config = True print u'Configuration of backend' @@ -155,16 +100,74 @@ def command_add(self, name, *options): except ConfigParser.DuplicateSectionError: print u'Instance "%s" already exists for backend "%s".' % (new_name, name) - @ConsoleApplication.command('List configured backends') + @ConsoleApplication.command('Show applications') + def command_applications(self, *caps): + applications = set() + import weboob.applications + for path in weboob.applications.__path__: + regexp = re.compile('^%s/([\w\d_]+)$' % path) + for root, dirs, files in os.walk(path): + m = regexp.match(root) + if m and '__init__.py' in files: + applications.add(m.group(1)) + print ' '.join(sorted(applications)).encode('utf-8') + + @ConsoleApplication.command('Show available backends') + def command_backends(self, *caps): + self.set_default_formatter('table') + self.weboob.backends_loader.load_all() + for name, backend in sorted(self.weboob.backends_loader.loaded.iteritems()): + if caps and not self.caps_included(backend.iter_caps(), caps): + continue + row = OrderedDict([('Name', name), + ('Capabilities', ', '.join(cap.__name__ for cap in backend.iter_caps())), + ('Description', backend.description), + ]) + self.format(row) + + @ConsoleApplication.command('Show configured backends') def command_configured(self): self.set_default_formatter('table') - for instance_name, name, params in self.weboob.backends_config.iter_backends(): + for instance_name, name, params in sorted(self.weboob.backends_config.iter_backends()): row = OrderedDict([('Instance name', instance_name), ('Backend name', name), ('Configuration', ', '.join('%s=%s' % (key, value) for key, value in params.iteritems())), ]) self.format(row) + @ConsoleApplication.command('Edit configuration file') + def command_edit(self): + subprocess.call([os.environ.get('EDITOR', 'vi'), self.weboob.backends_config.confpath]) + + @ConsoleApplication.command('Display information about a backend') + def command_info(self, name): + try: + backend = self.weboob.backends_loader.get_or_load_backend(name) + except KeyError: + logging.error('No such backend: "%s"' % name) + return 1 + + print '.------------------------------------------------------------------------------.' + print '| Backend %-68s |' % backend.name + print "+-----------------.------------------------------------------------------------'" + print '| Version | %s' % backend.version + print '| Maintainer | %s' % backend.maintainer + print '| License | %s' % backend.license + print '| Description | %s' % backend.description + print '| Capabilities | %s' % ', '.join([cap.__name__ for cap in backend.iter_caps()]) + first = True + for key, field in backend.config.iteritems(): + value = field.description + if not field.default is None: + value += ' (default: %s)' % field.default + if first: + print '| | ' + print '| Configuration | %s: %s' % (key, value) + first = False + else: + print '| | %s: %s' % (key, value) + print "'-----------------'" + @ConsoleApplication.command('Remove a configured backend') def command_remove(self, instance_name): try: @@ -172,7 +175,3 @@ def command_remove(self, instance_name): except ConfigParser.NoSectionError: logging.error('Backend instance "%s" does not exist' % instance_name) return 1 - - @ConsoleApplication.command('Edit configuration file') - def command_edit(self): - subprocess.call([os.environ.get('EDITOR', 'vi'), self.weboob.backends_config.confpath]) diff --git a/weboob/applications/weboobdebug/weboobdebug.py b/weboob/applications/weboobdebug/weboobdebug.py index dd46d616e881a1006a8b5388e244faa5d19d5de2..45ff70776fcf03881bfc55963f9ed0885b7b9a06 100644 --- a/weboob/applications/weboobdebug/weboobdebug.py +++ b/weboob/applications/weboobdebug/weboobdebug.py @@ -32,14 +32,14 @@ def main(self, argv): @ConsoleApplication.command('Debug backend') def command_shell(self, backend_name): try: - backend = self.weboob.load_modules(names=[backend_name])[backend_name] + backend = self.weboob.load_backends(names=[backend_name])[backend_name] except KeyError: logging.error(u'Unable to load backend "%s"' % backend_name) return 1 browser = backend.browser from IPython.Shell import IPShellEmbed shell = IPShellEmbed(argv=[]) - locs = dict(backend=backend, browser=browser, frontend=self, weboob=self.weboob) + locs = dict(backend=backend, browser=browser, application=self, weboob=self.weboob) banner = 'Weboob debug shell\nBackend "%s" loaded.\nAvailable variables: %s' % (backend_name, locs) shell.set_banner(shell.IP.BANNER + '\n\n' + banner) shell(local_ns=locs, global_ns={}) diff --git a/weboob/applications/weboobtests/weboobtests.py b/weboob/applications/weboobtests/weboobtests.py index 9a065ad8ea7da4ffaee99265c53249916284a86f..5e1af689b5601541fac0f2028f4651f246e0b040 100644 --- a/weboob/applications/weboobtests/weboobtests.py +++ b/weboob/applications/weboobtests/weboobtests.py @@ -15,6 +15,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + from nose import run from weboob.tools.application.console import ConsoleApplication @@ -32,13 +33,13 @@ def main(self, argv): @ConsoleApplication.command('Run tests') def command_run(self): - self.load_modules() self.load_backends() + self.load_configured_backends() suite = [] for backend in self.weboob.iter_backends(): - t = backend.get_test() - if t: - suite.append(t) + test = backend.get_test() + if test: + suite.append(test) return run(suite=suite) diff --git a/weboob/applications/weboorrents/weboorrents.py b/weboob/applications/weboorrents/weboorrents.py index 25f719c2a0116a7b1a3e1068d587e10a1551779d..f3c70e3826aa2fd92a11a0c4cef12ddcfce53afc 100644 --- a/weboob/applications/weboorrents/weboorrents.py +++ b/weboob/applications/weboorrents/weboorrents.py @@ -33,7 +33,7 @@ class Weboorrents(ConsoleApplication): CONFIG = {} def main(self, argv): - self.load_backends(ICapTorrent) + self.load_configured_backends(ICapTorrent) return self.process_command(*argv[1:]) @ConsoleApplication.command('Get information about a torrent') diff --git a/weboob/applications/wetboobs/wetboobs.py b/weboob/applications/wetboobs/wetboobs.py index 93b4ae31e2c7472d20fa5ec2da16d9a9e2f1ff85..4dc8887b3ca64103b9c00fb725463f523bc879db 100644 --- a/weboob/applications/wetboobs/wetboobs.py +++ b/weboob/applications/wetboobs/wetboobs.py @@ -32,7 +32,7 @@ class WetBoobs(ConsoleApplication): COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' def main(self, argv): - self.load_modules(ICapWeather) + self.load_backends(ICapWeather) return self.process_command(*argv[1:]) diff --git a/weboob/core/modules.py b/weboob/core/backends.py similarity index 69% rename from weboob/core/modules.py rename to weboob/core/backends.py index ac429352bd15d2616c0136d5159aed1f19b511df..30831f108e1a274a9e6dfb941b900d2726b6b342 100644 --- a/weboob/core/modules.py +++ b/weboob/core/backends.py @@ -26,45 +26,50 @@ import stat import weboob.backends -from weboob.core.backend import BaseBackend from weboob.capabilities.cap import ICap +from weboob.tools.backend import BaseBackend -__all__ = ['Module'] +__all__ = ['Backend', 'BackendsConfig', 'BackendsLoader'] -class Module(object): - def __init__(self, name, module): - self.name = name - self.module = module +class Backend(object): + def __init__(self, package): + self.package = package self.klass = None - for attrname in dir(self.module): - attr = getattr(self.module, attrname) + for attrname in dir(self.package): + attr = getattr(self.package, attrname) if isinstance(attr, type) and issubclass(attr, BaseBackend) and attr != BaseBackend: self.klass = attr - if not self.klass: - raise ImportError("This is not a backend module (no BaseBackend class found)") + raise ImportError('%s is not a backend (no BaseBackend class found)' % package) - def get_name(self): + @property + def name(self): return self.klass.NAME - def get_maintainer(self): + @property + def maintainer(self): return '%s <%s>' % (self.klass.MAINTAINER, self.klass.EMAIL) - def get_version(self): + @property + def version(self): return self.klass.VERSION - def get_description(self): + @property + def description(self): return self.klass.DESCRIPTION - def get_license(self): + @property + def license(self): return self.klass.LICENSE - def get_config(self): + @property + def config(self): return self.klass.CONFIG - def get_icon_path(self): + @property + def icon_path(self): return self.klass.ICON def iter_caps(self): @@ -78,9 +83,11 @@ def has_caps(self, *caps): return True return False - def create_backend(self, weboob, name, config, storage): - debug('Created backend "%s"' % name) - return self.klass(weboob, name, config, storage) + def create_instance(self, weboob, name, config, storage): + backend_instance = self.klass(weboob, name, config, storage) + debug('Created backend instance "%s"' % name) + return backend_instance + class BackendsConfig(object): class WrongPermissions(Exception): @@ -128,7 +135,7 @@ def get_backend(self, name): config = SafeConfigParser() config.read(self.confpath) if not config.has_section(name): - raise KeyError(u'Backend "%s" not found' % name) + raise KeyError(u'Backend instance "%s" not found' % name) items = dict(config.items(name, raw=True)) try: @@ -141,19 +148,20 @@ def remove_backend(self, name): config = SafeConfigParser() config.read(self.confpath) config.remove_section(name) - with open(self.confpath, 'wb') as f: + with open(self.confpath, 'w') as f: config.write(f) -class ModulesLoader(object): + +class BackendsLoader(object): def __init__(self): - self.modules = {} + self.loaded = {} - def get_or_load_module(self, name): - if name not in self.modules: - self.load_module('weboob.backends.%s' % name) - return self.modules[name] + def get_or_load_backend(self, name): + if name not in self.loaded: + self.load_backend(name) + return self.loaded[name] - def iter_existing_module_names(self): + def iter_existing_backend_names(self): for path in weboob.backends.__path__: regexp = re.compile('^%s/([\w\d_]+)$' % path) for root, dirs, files in os.walk(path): @@ -161,23 +169,24 @@ def iter_existing_module_names(self): if m and '__init__.py' in files: yield m.group(1) - def load(self): - for existing_module_name in self.iter_existing_module_names(): - self.load_module('weboob.backends.%s' % existing_module_name) + def load_all(self): + for existing_backend_name in self.iter_existing_backend_names(): + self.load_backend(existing_backend_name) - def load_module(self, name): + def load_backend(self, name): try: - module = Module(name, __import__(name, fromlist=[str(name)])) + package_name = 'weboob.backends.%s' % name + backend = Backend(__import__(package_name, fromlist=[str(package_name)])) except ImportError, e: - msg = 'Unable to load module "%s": %s' % (name, e) + msg = u'Unable to load backend "%s": %s' % (name, e) if logging.root.level == logging.DEBUG: exception(msg) return else: error(msg) return - if module.get_name() in self.modules: - warning('Module "%s" is already loaded (%s)' % (self.modules[module.get_name()].module, name)) + if backend.name in self.loaded: + debug('Backend "%s" is already loaded from %s' % (name, backend.package.__path__[0])) return - self.modules[module.get_name()] = module - debug('Loaded module "%s" from %s' % (name, module.module.__path__)) + self.loaded[backend.name] = backend + debug('Loaded backend "%s" from %s' % (name, backend.package.__path__[0])) diff --git a/weboob/core/ouiboube.py b/weboob/core/ouiboube.py index febdeffec903022993d6edac25f8d4a1a435395b..f1e2b159e4d9f5d7ee877d037b0f64563dba607d 100644 --- a/weboob/core/ouiboube.py +++ b/weboob/core/ouiboube.py @@ -23,9 +23,9 @@ import sys from weboob.core.bcall import BackendsCall -from weboob.core.modules import ModulesLoader, BackendsConfig -from weboob.core.backend import BaseBackend +from weboob.core.backends import BackendsConfig, BackendsLoader from weboob.core.scheduler import Scheduler +from weboob.tools.backend import BaseBackend if sys.version_info[:2] <= (2, 5): import weboob.tools.property @@ -40,7 +40,7 @@ class Weboob(object): def __init__(self, workdir=WORKDIR, backends_filename=None, scheduler=None): self.workdir = workdir - self.backends = {} + self.backend_instances = {} # Scheduler if scheduler is None: @@ -53,10 +53,10 @@ def __init__(self, workdir=WORKDIR, backends_filename=None, scheduler=None): elif not os.path.isdir(self.workdir): warning('"%s" is not a directory' % self.workdir) - # Modules loader - self.modules_loader = ModulesLoader() + # Backends loader + self.backends_loader = BackendsLoader() - # Backends config + # Backend instances config if not backends_filename: backends_filename = os.path.join(self.workdir, self.BACKENDS_FILENAME) elif not backends_filename.startswith('/'): @@ -64,41 +64,26 @@ def __init__(self, workdir=WORKDIR, backends_filename=None, scheduler=None): self.backends_config = BackendsConfig(backends_filename) def load_backends(self, caps=None, names=None, storage=None): - loaded_backends = {} - for name, _type, params in self.backends_config.iter_backends(): - try: - module = self.modules_loader.get_or_load_module(_type) - except KeyError: - warning(u'Unable to find module "%s" for backend "%s"' % (_type, name)) + loaded = {} + self.backends_loader.load_all() + for backend_name, backend in self.backends_loader.loaded.iteritems(): + if caps is not None and not backend.has_caps(caps) or \ + names is not None and backend_name not in names: continue - - # Check conditions - if caps is not None and not module.has_caps(caps) or \ - names is not None and name not in names: - continue - - try: - self.backends[name] = module.create_backend(self, name, params, storage) - loaded_backends[name] = self.backends[name] - except Exception, e: - warning(u'Unable to load "%s" backend: %s. filename=%s' % (name, e, self.backends_config.confpath)) - - return loaded_backends - - def load_modules(self, caps=None, names=None, storage=None): - loaded_backends = {} - self.modules_loader.load() - for name, module in self.modules_loader.modules.iteritems(): - if caps is not None and not module.has_caps(caps) or \ - names is not None and name not in names: + backend_instance = backend.create_instance(self, backend_name, {}, storage) + self.backend_instances[backend_name] = loaded[backend_name] = backend_instance + return loaded + + def load_configured_backends(self, caps=None, names=None, storage=None): + loaded = {} + for instance_name, backend_name, params in self.backends_config.iter_backends(): + backend = self.backends_loader.get_or_load_backend(backend_name) + if caps is not None and not backend.has_caps(caps) or \ + names is not None and instance_name not in names: continue - try: - name = module.get_name() - self.backends[name] = module.create_backend(self, name, {}, storage) - loaded_backends[name] = self.backends[name] - except Exception, e: - warning(u'Unable to load "%s" module as backend with no config: %s' % (name, e)) - return loaded_backends + backend_instance = backend.create_instance(self, instance_name, params, storage) + self.backend_instances[instance_name] = loaded[instance_name] = backend_instance + return loaded def iter_backends(self, caps=None): """ @@ -109,7 +94,7 @@ def iter_backends(self, caps=None): @param caps Optional list of capabilities to select backends @return iterator on selected backends. """ - for name, backend in sorted(self.backends.iteritems()): + for name, backend in sorted(self.backend_instances.iteritems()): if caps is None or backend.has_caps(caps): with backend: yield backend @@ -134,7 +119,7 @@ def do(self, function, *args, **kwargs): def do_caps(self, caps, function, *args, **kwargs): """ - Do calls on loaded modules with the specified capabilities, in + Do calls on loaded backends with the specified capabilities, in separated threads. See also documentation of the 'do' method. @@ -156,14 +141,14 @@ def do_backends(self, backends, function, *args, **kwargs): elif isinstance(backends, (list,tuple)): old_backends = backends backends = [] - for b in old_backends: - if isinstance(b, (str,unicode)): + for backend in old_backends: + if isinstance(backend, (str,unicode)): try: - backends.append(self.backends[self.backends.index(b)]) + backends.append(self.backends[self.backends.index(backend)]) except ValueError: pass else: - backends.append(b) + backends.append(backend) return BackendsCall(backends, function, *args, **kwargs) def schedule(self, interval, function, *args): diff --git a/weboob/tools/application/base.py b/weboob/tools/application/base.py index e3de6d4a23c039d0fa5746d70c3a8a06a4754dcf..5260b3b7aaa97c09138de3f27b409ad304281422 100644 --- a/weboob/tools/application/base.py +++ b/weboob/tools/application/base.py @@ -32,28 +32,28 @@ class BackendNotFound(Exception): pass -class FrontendStorage(object): +class ApplicationStorage(object): def __init__(self, name, storage): self.name = name self.storage = storage def set(self, *args): if self.storage: - return self.storage.set('frontends', self.name, *args) + return self.storage.set('applications', self.name, *args) def get(self, *args, **kwargs): if self.storage: - return self.storage.get('frontends', self.name, *args, **kwargs) + return self.storage.get('applications', self.name, *args, **kwargs) else: return kwargs.get('default', None) def load(self, default): if self.storage: - return self.storage.load('frontends', self.name, default) + return self.storage.load('applications', self.name, default) def save(self): if self.storage: - return self.storage.save('frontends', self.name) + return self.storage.save('applications', self.name) class BaseApplication(object): # Application name @@ -107,7 +107,7 @@ def create_storage(self, path=None, klass=None): path = os.path.join(self.CONFDIR, path) storage = klass(path) - self.storage = FrontendStorage(self.APPNAME, storage) + self.storage = ApplicationStorage(self.APPNAME, storage) self.storage.load(self.STORAGE) return storage @@ -138,18 +138,18 @@ def main(self, argv): def load_backends(self, caps=None, names=None, *args, **kwargs): if names is None: names = self.requested_backends - loaded_backends = self.weboob.load_backends(caps, names, *args, **kwargs) - if not loaded_backends: + loaded = self.weboob.load_backends(caps, names, *args, **kwargs) + if not loaded: logging.warning(u'No backend loaded') - return loaded_backends + return loaded - def load_modules(self, caps=None, names=None, *args, **kwargs): + def load_configured_backends(self, caps=None, names=None, *args, **kwargs): if names is None: names = self.requested_backends - loaded_modules = self.weboob.load_modules(caps, names, *args, **kwargs) - if not loaded_modules: - logging.warning(u'No module loaded') - return loaded_modules + loaded = self.weboob.load_configured_backends(caps, names, *args, **kwargs) + if not loaded: + logging.warning(u'No configured backend loaded') + return loaded def _get_completions(self): """ @@ -201,9 +201,9 @@ def run(klass, args=None): logging.basicConfig(stream=sys.stdout, level=level, format=log_format) app.requested_backends = app.options.backends.split(',') if app.options.backends else None if app.requested_backends: - existing_module_names = list(app.weboob.modules_loader.iter_existing_module_names()) + existing_backend_names = list(app.weboob.backends_loader.iter_existing_backend_names()) for requested_backend in app.requested_backends: - if requested_backend not in existing_module_names: + if requested_backend not in existing_backend_names: raise BackendNotFound(u'Unknown backend: "%s"' % requested_backend) app._handle_app_options() diff --git a/weboob/tools/application/console.py b/weboob/tools/application/console.py index 962acce27c42ba5eef652577ecc872570df1de5a..76eb4c0926b04adb54d290d18ac69f2d4995839f 100644 --- a/weboob/tools/application/console.py +++ b/weboob/tools/application/console.py @@ -24,7 +24,7 @@ import sys from weboob.core import CallErrors -from weboob.core.modules import BackendsConfig +from weboob.core.backends import BackendsConfig from .base import BackendNotFound, BaseApplication from .formatters.load import formatters, load_formatter diff --git a/weboob/tools/application/qt/backendcfg.py b/weboob/tools/application/qt/backendcfg.py index d8af23baeb726500ef3138f21c60753c80b3e340..62189c5aed982767216cfda782e0aed5180e73d9 100644 --- a/weboob/tools/application/qt/backendcfg.py +++ b/weboob/tools/application/qt/backendcfg.py @@ -35,50 +35,50 @@ def __init__(self, weboob, caps=None, parent=None): self.caps = caps self.config_widgets = {} - self.weboob.modules_loader.load() + self.weboob.backends_loader.load_all() - self.ui.backendsList.header().setResizeMode(QHeaderView.ResizeToContents) + self.ui.configuredBackendsList.header().setResizeMode(QHeaderView.ResizeToContents) self.ui.configFrame.hide() - for name, module in self.weboob.modules_loader.modules.iteritems(): - if not self.caps or module.has_caps(*self.caps): + for name, backend in self.weboob.backends_loader.loaded.iteritems(): + if not self.caps or backend.has_caps(*self.caps): item = QListWidgetItem(name.capitalize()) - if module.get_icon_path(): - img = QImage(module.get_icon_path()) + if backend.icon_path: + img = QImage(backend.icon_path) item.setIcon(QIcon(QPixmap.fromImage(img))) - self.ui.modulesList.addItem(item) + self.ui.backendsList.addItem(item) - self.loadBackendsList() + self.loadConfiguredBackendsList() - self.connect(self.ui.backendsList, SIGNAL('itemClicked(QTreeWidgetItem *, int)'), self.backendClicked) - self.connect(self.ui.modulesList, SIGNAL('itemSelectionChanged()'), self.modulesSelectionChanged) + self.connect(self.ui.configuredBackendsList, SIGNAL('itemClicked(QTreeWidgetItem *, int)'), self.configuredBackendClicked) + self.connect(self.ui.backendsList, SIGNAL('itemSelectionChanged()'), self.backendSelectionChanged) self.connect(self.ui.proxyBox, SIGNAL('toggled(bool)'), self.proxyEditEnabled) self.connect(self.ui.addButton, SIGNAL('clicked()'), self.addEvent) self.connect(self.ui.removeButton, SIGNAL('clicked()'), self.removeEvent) self.connect(self.ui.configButtonBox, SIGNAL('accepted()'), self.acceptBackend) self.connect(self.ui.configButtonBox, SIGNAL('rejected()'), self.rejectBackend) - def loadBackendsList(self): - self.ui.backendsList.clear() + def loadConfiguredBackendsList(self): + self.ui.configuredBackendsList.clear() for instance_name, name, params in self.weboob.backends_config.iter_backends(): - module = self.weboob.modules_loader.modules[name] - if self.caps and not module.has_caps(*self.caps): + backend = self.weboob.backends_loader.loaded[name] + if self.caps and not backend.has_caps(*self.caps): continue item = QTreeWidgetItem(None, [instance_name, name]) - if module.get_icon_path(): - img = QImage(module.get_icon_path()) + if backend.icon_path: + img = QImage(backend.icon_path) item.setIcon(0, QIcon(QPixmap.fromImage(img))) - self.ui.backendsList.addTopLevelItem(item) + self.ui.configuredBackendsList.addTopLevelItem(item) def closeEvent(self, event): event.accept() - def backendClicked(self, item, col): + def configuredBackendClicked(self, item, col): bname = unicode(item.text(0)) self.editBackend(bname) @@ -87,7 +87,7 @@ def addEvent(self): self.editBackend() def removeEvent(self): - item = self.ui.backendsList.currentItem() + item = self.ui.configuredBackendsList.currentItem() if not item: return @@ -100,7 +100,7 @@ def removeEvent(self): return self.weboob.backends_config.remove_backend(bname) - self.loadBackendsList() + self.loadConfiguredBackendsList() def editBackend(self, bname=None): self.ui.configFrame.show() @@ -108,12 +108,12 @@ def editBackend(self, bname=None): if bname is not None: mname, params = self.weboob.backends_config.get_backend(bname) - items = self.ui.modulesList.findItems(mname, Qt.MatchFixedString) + items = self.ui.backendsList.findItems(mname, Qt.MatchFixedString) if not items: - print 'Module not found' + print 'Backend not found' else: - self.ui.modulesList.setCurrentItem(items[0]) - self.ui.modulesList.setEnabled(False) + self.ui.backendsList.setCurrentItem(items[0]) + self.ui.backendsList.setEnabled(False) self.ui.nameEdit.setText(bname) self.ui.nameEdit.setEnabled(False) @@ -137,19 +137,19 @@ def editBackend(self, bname=None): self.ui.nameEdit.setEnabled(True) self.ui.proxyBox.setChecked(False) self.ui.proxyEdit.clear() - self.ui.modulesList.setEnabled(True) - self.ui.modulesList.setCurrentRow(-1) + self.ui.backendsList.setEnabled(True) + self.ui.backendsList.setCurrentRow(-1) def acceptBackend(self): bname = unicode(self.ui.nameEdit.text()) - selection = self.ui.modulesList.selectedItems() + selection = self.ui.backendsList.selectedItems() if not selection: - QMessageBox.critical(self, self.tr('Unable to add a backend'), - self.tr('Please select a module')) + QMessageBox.critical(self, self.tr('Unable to add a configured backend'), + self.tr('Please select a backend')) return - module = self.weboob.modules_loader.modules[unicode(selection[0].text()).lower()] + backend = self.weboob.backends_loader.loaded[unicode(selection[0].text()).lower()] params = {} missing = [] @@ -162,7 +162,7 @@ def acceptBackend(self): if not params['_proxy']: missing.append(self.tr('Proxy')) - for key, field in module.get_config().iteritems(): + for key, field in backend.config.iteritems(): label, value = self.config_widgets[key] if isinstance(value, QLineEdit): @@ -189,49 +189,49 @@ def acceptBackend(self): unicode(self.tr('Please set a value in this fields:\n%s')) % ('\n'.join(['- %s' % s for s in missing]))) return - self.weboob.backends_config.add_backend(bname, module.get_name(), params, edit=not self.ui.nameEdit.isEnabled()) + self.weboob.backends_config.add_backend(bname, backend.name, params, edit=not self.ui.nameEdit.isEnabled()) self.ui.configFrame.hide() - self.loadBackendsList() + self.loadConfiguredBackendsList() def rejectBackend(self): self.ui.configFrame.hide() - def modulesSelectionChanged(self): + def backendSelectionChanged(self): for key, (label, value) in self.config_widgets.iteritems(): label.hide() value.hide() self.ui.configLayout.removeWidget(label) self.ui.configLayout.removeWidget(value) self.config_widgets.clear() - self.ui.moduleInfo.clear() + self.ui.backendInfo.clear() - selection = self.ui.modulesList.selectedItems() + selection = self.ui.backendsList.selectedItems() if not selection: return - module = self.weboob.modules_loader.modules[unicode(selection[0].text()).lower()] + backend = self.weboob.backends_loader.loaded[unicode(selection[0].text()).lower()] - if module.get_icon_path(): - img = QImage(module.get_icon_path()) - self.ui.moduleInfo.document().addResource(QTextDocument.ImageResource, QUrl('mydata://logo.png'), QVariant(img)) + if backend.icon_path: + img = QImage(backend.icon_path) + self.ui.backendInfo.document().addResource(QTextDocument.ImageResource, QUrl('mydata://logo.png'), QVariant(img)) - self.ui.moduleInfo.setText(unicode(self.tr( - '

%s Module %s

' + self.ui.backendInfo.setText(unicode(self.tr( + '

%s Backend %s

' 'Version: %s
' 'Maintainer: %s
' 'License: %s
' 'Description: %s
' 'Capabilities: %s
')) - % ('' if module.get_icon_path() else '', - module.get_name().capitalize(), - module.get_version(), - module.get_maintainer().replace('&', '&').replace('<', '<').replace('>', '>'), - module.get_license(), - module.get_description(), - ', '.join([cap.__name__ for cap in module.iter_caps()]))) - - for key, field in module.get_config().iteritems(): + % ('' if backend.icon_path else '', + backend.name.capitalize(), + backend.version, + backend.maintainer.replace('&', '&').replace('<', '<').replace('>', '>'), + backend.license, + backend.description, + ', '.join([cap.__name__ for cap in backend.iter_caps()]))) + + for key, field in backend.config.iteritems(): label = QLabel(u'%s:' % field.description) if isinstance(field.default, bool): value = QCheckBox() diff --git a/weboob/tools/application/qt/backendcfg.ui b/weboob/tools/application/qt/backendcfg.ui index 2cf3d7e5f5fb66ca1f150809b21f98623391e21e..e6597f850fe83adf51f898bad8e7a0a89077e14a 100644 --- a/weboob/tools/application/qt/backendcfg.ui +++ b/weboob/tools/application/qt/backendcfg.ui @@ -6,8 +6,8 @@ 0 0 - 626 - 614 + 645 + 652 @@ -22,7 +22,7 @@ - + QAbstractItemView::NoEditTriggers @@ -72,7 +72,7 @@ - Module + Backend @@ -125,99 +125,107 @@ QFrame::Raised - + - - - Qt::Horizontal + + + + + Available backends + + + + + + + + 0 + 0 + + + + + 32 + 32 + + + + 1 + + + true + + + + + + + + + + 1 + 0 + - - - - 0 - 0 - - - - - 32 - 32 - - - - 1 - - - true - - - - - - 1 - 0 - - - - QFrame::NoFrame - - - QFrame::Plain - - - - - - - - Name: - - - - - - - - - - Proxy: - - - - - - - false - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - 0 - 0 - - - - true - - - - - + + QFrame::NoFrame + + + QFrame::Plain + + + + + + + 0 + 0 + + + + true + + + + + + + + + Name: + + + + + + + + + + Proxy: + + + + + + + false + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + +