From 6dfbda042c37262f68fc502b2dbcd4229fcf9461 Mon Sep 17 00:00:00 2001 From: Romain Bignon Date: Thu, 30 Sep 2010 11:59:12 +0200 Subject: [PATCH] correctly handle BrowserUnavailable and BrowserIncorrectPassword exceptions in repl applications (closes #302) It asks user to reconfigure backend when BrowserIncorrectPassword is raised. --- weboob/applications/boobank/boobank.py | 22 +++----- weboob/core/bcall.py | 2 +- weboob/core/ouiboube.py | 4 ++ weboob/tools/application/repl.py | 70 ++++++++++++++++++++------ 4 files changed, 67 insertions(+), 31 deletions(-) diff --git a/weboob/applications/boobank/boobank.py b/weboob/applications/boobank/boobank.py index c30888fc..7d60f721 100644 --- a/weboob/applications/boobank/boobank.py +++ b/weboob/applications/boobank/boobank.py @@ -19,7 +19,6 @@ from __future__ import with_statement import logging -import weboob from weboob.capabilities.bank import ICapBank from weboob.tools.application.repl import ReplApplication @@ -44,18 +43,11 @@ class Boobank(ReplApplication): tot_balance = 0.0 tot_coming = 0.0 self.accounts = [] - try: - for backend, account in self.do('iter_accounts'): - self.format(account) - tot_balance += account.balance - tot_coming += account.coming - self.accounts.append(account) - except weboob.core.CallErrors, errors: - for backend, error, backtrace in errors: - if isinstance(error, weboob.tools.browser.BrowserIncorrectPassword): - logging.error(u'Error: Incorrect password for backend %s' % backend.name) - else: - logging.error(u'Error[%s]: %s\n%s' % (backend.name, error, backtrace)) + for backend, account in self.do('iter_accounts'): + self.format(account) + tot_balance += account.balance + tot_coming += account.coming + self.accounts.append(account) else: self.format((('label', 'Total'), ('balance', tot_balance), @@ -127,13 +119,13 @@ class Boobank(ReplApplication): id_from, backend_name_from = self.parse_id(id_from) id_to, backend_name_to = self.parse_id(id_to) - + if backend_name_from != backend_name_to: print "Transfer between different backend is not implemented" return else: backend_name = backend_name_from - + names = (backend_name,) if backend_name is not None else None self.load_backends(ICapBank, names=names) diff --git a/weboob/core/bcall.py b/weboob/core/bcall.py index e5853940..6d5b0c1a 100644 --- a/weboob/core/bcall.py +++ b/weboob/core/bcall.py @@ -34,7 +34,7 @@ class CallErrors(Exception): def __init__(self, errors): Exception.__init__(self, u'These errors have been raised in backend threads '\ '(use --debug option to print backtraces):\n%s' % ( - u'\n'.join((u' * %s: %s%s' % (backend, repr(error), backtrace.decode('utf-8') + '\n' + u'\n'.join((u' * %s: %s%s' % (backend.name, repr(error), backtrace.decode('utf-8') + '\n' if logging.root.level == logging.DEBUG else '')) for backend, error, backtrace in errors))) self.errors = copy(errors) diff --git a/weboob/core/ouiboube.py b/weboob/core/ouiboube.py index 29f39ead..ba46f569 100644 --- a/weboob/core/ouiboube.py +++ b/weboob/core/ouiboube.py @@ -97,6 +97,7 @@ class Weboob(object): return loaded def unload_backends(self, names=None): + unloaded = {} if isinstance(names, basestring): names = [names] elif names is None: @@ -106,6 +107,9 @@ class Weboob(object): backend = self.backend_instances.pop(name) with backend: backend.deinit() + unloaded[backend.name] = backend + + return unloaded def get_backend(self, name): return self.backend_instances[name] diff --git a/weboob/tools/application/repl.py b/weboob/tools/application/repl.py index fa8298ee..0d03c924 100644 --- a/weboob/tools/application/repl.py +++ b/weboob/tools/application/repl.py @@ -31,6 +31,7 @@ from weboob.capabilities.base import FieldNotFound from weboob.core import CallErrors from weboob.core.backendscfg import BackendsConfig, BackendAlreadyExists from weboob.tools.misc import iter_fields +from weboob.tools.browser import BrowserUnavailable, BrowserIncorrectPassword from .base import BackendNotFound, BaseApplication from .formatters.load import formatters as available_formatters, load_formatter @@ -119,7 +120,7 @@ class ReplApplication(Cmd, BaseApplication): atexit.register(savehist) self._interactive = False - self.enabled_backends = [] + self.enabled_backends = set() @property def interactive(self): @@ -134,10 +135,20 @@ class ReplApplication(Cmd, BaseApplication): return False return True - def add_backend(self, name, params=None): + def edit_backend(self, name, params=None): + return self.add_backend(name, params, True) + + def add_backend(self, name, params=None, edit=False): if params is None: params = {} - backend = self.weboob.modules_loader.get_or_load_module(name) + + if not edit: + backend = self.weboob.modules_loader.get_or_load_module(name) + else: + bname, items = self.weboob.backends_config.get_backend(name) + backend = self.weboob.modules_loader.get_or_load_module(bname) + items.update(params) + params = items if not backend: print 'Backend "%s" does not exist.' % name return None @@ -149,9 +160,9 @@ class ReplApplication(Cmd, BaseApplication): asked_config = True print 'Configuration of backend' print '------------------------' - if key not in params: + if key not in params or edit: params[key] = self.ask(' [%s] %s' % (key, value.description), - default=value.default, + default=params[key] if (edit and key in params) else value.default, masked=value.is_masked, choices=value.choices, regexp=value.regexp) @@ -161,10 +172,10 @@ class ReplApplication(Cmd, BaseApplication): print '------------------------' try: - self.weboob.backends_config.add_backend(name, name, params) - print 'Backend "%s" successfully added.' % name + self.weboob.backends_config.add_backend(name, name, params, edit=edit) + print 'Backend "%s" successfully %s.' % (name, 'updated' if edit else 'added') return name - except BackendAlreadyExists:#ConfigParser.DuplicateSectionError: + except BackendAlreadyExists: print 'Backend "%s" is already configured in file "%s"' % (name, self.weboob.backends_config.confpath) while self.ask('Add new instance of "%s" backend?' % name, default=False): new_name = self.ask('Please give new instance name (could be "%s_1")' % name, regexp=u'^[\d\w_-]+$') @@ -175,10 +186,19 @@ class ReplApplication(Cmd, BaseApplication): except BackendAlreadyExists: print 'Instance "%s" already exists for backend "%s".' % (new_name, name) + def unload_backends(self, *args, **kwargs): + unloaded = self.weboob.unload_backends(*args, **kwargs) + for backend in unloaded.itervalues(): + try: + self.enabled_backends.remove(backend) + except ValueError: + pass + return unloaded + def load_backends(self, *args, **kwargs): ret = super(ReplApplication, self).load_backends(*args, **kwargs) for name, backend in ret.iteritems(): - self.enabled_backends.append(backend) + self.enabled_backends.add(backend) while len(self.enabled_backends) == 0: print 'Warning: there is currently no configured backend for %s' % self.APPNAME if not self.ask('Do you want to configure backends?', default=True): @@ -264,7 +284,31 @@ class ReplApplication(Cmd, BaseApplication): try: return super(ReplApplication, self).onecmd(_cmd) except CallErrors, e: - print >>sys.stderr, '%s' % e + ask_debug_mode = False + for backend, error, backtrace in e.errors: + if isinstance(error, BrowserIncorrectPassword): + msg = unicode(error) + if not msg: + msg = 'invalid login/password.' + print >>sys.stderr, 'Error(%s): %s' % (backend.name, msg) + if self.ask('Do you want to reconfigure this backend?', default=True): + self.unload_backends(names=[backend.name]) + self.edit_backend(backend.name) + self.load_backends(names=[backend.name]) + elif isinstance(error, BrowserUnavailable): + msg = unicode(error) + if not msg: + msg = 'website is unavailable.' + print >>sys.stderr, 'Error(%s): %s' % (backend.name, msg) + else: + common_errors = True + print >>sys.stderr, 'Error(%s): %s' % (backend.name, error) + if logging.root.level == logging.DEBUG: + print >>sys.stderr, backtrace + else: + ask_debug_mode = True + if ask_debug_mode: + print >>sys.stderr, 'Use --debug option to print backtraces.' except NotEnoughArguments, e: print >>sys.stderr, 'Error: no enough arguments.' except (KeyboardInterrupt,EOFError): @@ -507,11 +551,7 @@ class ReplApplication(Cmd, BaseApplication): elif action == 'remove': for backend in given_backends: self.weboob.backends_config.remove_backend(backend.name) - self.weboob.unload_backends(backend.name) - try: - self.enabled_backends.remove(backend) - except ValueError: - pass + self.unload_backends(backend.name) else: print 'Unknown action: "%s"' % action return 1