diff --git a/weboob/applications/cineoob/cineoob.py b/weboob/applications/cineoob/cineoob.py index f5659ccf..ea631685 100644 --- a/weboob/applications/cineoob/cineoob.py +++ b/weboob/applications/cineoob/cineoob.py @@ -574,22 +574,18 @@ class Cineoob(ReplApplication): if dest is None: dest = '%s' % _id - try: - for backend, buf in self.do('get_subtitle_file', _id, backends=backend_name, caps=ICapSubtitle): - if buf: - if dest == '-': - print buf - else: - try: - with open(dest, 'w') as f: - f.write(buf) - except IOError as e: - print >>sys.stderr, 'Unable to write file in "%s": %s' % (dest, e) - return 1 - return - except CallErrors as errors: - for backend, error, backtrace in errors: - self.bcall_error_handler(backend, error, backtrace) + for backend, buf in self.do('get_subtitle_file', _id, backends=backend_name, caps=ICapSubtitle): + if buf: + if dest == '-': + print buf + else: + try: + with open(dest, 'w') as f: + f.write(buf) + except IOError as e: + print >>sys.stderr, 'Unable to write file in "%s": %s' % (dest, e) + return 1 + return print >>sys.stderr, 'Subtitle "%s" not found' % id return 3 diff --git a/weboob/core/bcall.py b/weboob/core/bcall.py index 3c8c1ac8..8307bd33 100644 --- a/weboob/core/bcall.py +++ b/weboob/core/bcall.py @@ -56,10 +56,12 @@ class ResultsConditionError(Exception): class BackendsCall(object): def __init__(self, backends, condition, function, *args, **kwargs): """ - @param backends list of backends to call. - @param condition a IResultsCondition object. Can be None. - @param function backends' method name, or callable object. - @param args, kwargs arguments given to called functions. + :param backends: List of backends to call + :type backends: list[:class:`BaseBackend`] + :param condition: Condition applied on results (can be None) + :type condition: :class:`IResultsCondition` + :param function: backends' method name, or callable object. + :type function: :class:`str` or :class:`callable` """ self.logger = getLogger('bcall') # Store if a backend is finished diff --git a/weboob/tools/application/base.py b/weboob/tools/application/base.py index 099c8484..56a9cdc0 100644 --- a/weboob/tools/application/base.py +++ b/weboob/tools/application/base.py @@ -37,6 +37,9 @@ from weboob.tools.misc import to_unicode __all__ = ['BaseApplication'] +class MoreResultsAvailable(Exception): + pass + class ApplicationStorage(object): def __init__(self, name, storage): self.name = name @@ -164,10 +167,13 @@ class BaseApplication(object): """ Create a storage object. - @param path [str] an optional specific path. - @param klass [IStorage] what klass to instance. - @param localonly [bool] if True, do not set it on the Weboob object. - @return a IStorage object + :param path: An optional specific path + :type path: :class:`str` + :param klass: What class to instance + :type klass: :class:`weboob.tools.storage.IStorage` + :param localonly: If True, do not set it on the :class:`Weboob` object. + :type localonly: :class:`bool` + :rtype: :class:`weboob.tools.storage.IStorage` """ if klass is None: from weboob.tools.storage import StandardStorage @@ -191,9 +197,11 @@ class BaseApplication(object): """ Load a configuration file and get his object. - @param path [str] an optional specific path. - @param klass [IConfig] what klass to instance. - @return a IConfig object + :param path: An optional specific path + :type path: :class:`str` + :param klass: What class to instance + :type klass: :class:`weboob.tools.config.iconfig.IConfig` + :rtype: :class:`weboob.tools.config.iconfig.IConfig` """ if klass is None: from weboob.tools.config.iniconfig import INIConfig @@ -242,7 +250,7 @@ class BaseApplication(object): def _do_complete_iter(self, backend, count, fields, res): for i, sub in enumerate(res): if count and i == count: - break + raise MoreResultsAvailable() sub = self._do_complete_obj(backend, fields, sub) yield sub @@ -264,18 +272,39 @@ class BaseApplication(object): This method can be overrided to support more exceptions types. """ + + # Ignore this error. + if isinstance(error, MoreResultsAvailable): + return False + print >>sys.stderr, u'Error(%s): %s' % (backend.name, error) if logging.root.level == logging.DEBUG: print >>sys.stderr, backtrace + else: + return True - def bcall_errors_handler(self, errors): + def bcall_errors_handler(self, errors, debugmsg='Use --debug option to print backtraces', ignore=()): """ Handler for the CallErrors exception. + + It calls `bcall_error_handler` for each error. + + :param errors: Object containing errors from backends + :type errors: :class:`weboob.core.bcall.CallErrors` + :param debugmsg: Default message asking to enable the debug mode + :type debugmsg: :class:`basestring` + :param ignore: Exceptions to ignore + :type ignore: tuple[:class:`Exception`] """ + ask_debug_mode = False for backend, error, backtrace in errors.errors: - self.bcall_error_handler(backend, error, backtrace) - if logging.root.level != logging.DEBUG: - print >>sys.stderr, 'Use --debug option to print backtraces.' + if isinstance(error, ignore): + continue + elif self.bcall_error_handler(backend, error, backtrace): + ask_debug_mode = True + + if ask_debug_mode: + print >>sys.stderr, debugmsg def parse_args(self, args): self.options, args = self._parser.parse_args(args) @@ -372,6 +401,7 @@ class BaseApplication(object): a call to sys.exit(). For example: + >>> from weboob.application.myapplication import MyApplication >>> MyApplication.run() """ diff --git a/weboob/tools/application/console.py b/weboob/tools/application/console.py index 16c165ce..5213775f 100644 --- a/weboob/tools/application/console.py +++ b/weboob/tools/application/console.py @@ -37,7 +37,7 @@ from weboob.tools.browser import BrowserUnavailable, BrowserIncorrectPassword, B from weboob.tools.value import Value, ValueBool, ValueFloat, ValueInt from weboob.tools.misc import to_unicode -from .base import BaseApplication +from .base import BaseApplication, MoreResultsAvailable __all__ = ['ConsoleApplication', 'BackendNotGiven'] @@ -497,6 +497,8 @@ class ConsoleApplication(BaseApplication): print >>sys.stderr, u' %s please contact: %s <%s>' % (' ' * len(backend.name), backend.MAINTAINER, backend.EMAIL) elif isinstance(error, UserError): print >>sys.stderr, u'Error(%s): %s' % (backend.name, to_unicode(error)) + elif isinstance(error, MoreResultsAvailable): + print >>sys.stderr, u'Hint: There are more results for backend %s' % (backend.name) elif isinstance(error, SSLError): print >>sys.stderr, u'FATAL(%s): ' % backend.name + self.BOLD + '/!\ SERVER CERTIFICATE IS INVALID /!\\' + self.NC else: @@ -519,14 +521,21 @@ class ConsoleApplication(BaseApplication): else: return True - def bcall_errors_handler(self, errors, debugmsg='Use --debug option to print backtraces'): + def bcall_errors_handler(self, errors, debugmsg='Use --debug option to print backtraces', ignore=()): """ Handler for the CallErrors exception. """ ask_debug_mode = False + more_results = set() for backend, error, backtrace in errors.errors: - if self.bcall_error_handler(backend, error, backtrace): + if isinstance(error, MoreResultsAvailable): + more_results.add(backend.name) + elif isinstance(error, ignore): + continue + elif self.bcall_error_handler(backend, error, backtrace): ask_debug_mode = True if ask_debug_mode: print >>sys.stderr, debugmsg + elif len(more_results) > 0: + print >>sys.stderr, 'Hint: There are more results available for %s' % (', '.join(more_results)) diff --git a/weboob/tools/application/qt/qt.py b/weboob/tools/application/qt/qt.py index 578a2b19..4f958f27 100644 --- a/weboob/tools/application/qt/qt.py +++ b/weboob/tools/application/qt/qt.py @@ -37,7 +37,7 @@ from weboob.tools.value import ValueInt, ValueBool, ValueBackendPassword from weboob.tools.misc import to_unicode from weboob.capabilities import UserError -from ..base import BaseApplication +from ..base import BaseApplication, MoreResultsAvailable __all__ = ['QtApplication', 'QtMainWindow', 'QtDo', 'HTMLDelegate'] @@ -201,6 +201,10 @@ class QtDo(QObject): self.process.callback_thread(self.thread_cb, self.thread_eb) def default_eb(self, backend, error, backtrace): + if isinstance(error, MoreResultsAvailable): + # This is not an error, ignore. + return + msg = unicode(error) if isinstance(error, BrowserIncorrectPassword): if not msg: @@ -247,9 +251,6 @@ class QtDo(QObject): def local_eb(self, backend, error, backtrace): self.eb(backend, error, backtrace) - self.disconnect(self, SIGNAL('cb'), self.local_cb) - self.disconnect(self, SIGNAL('eb'), self.local_eb) - self.process = None def thread_cb(self, backend, data): self.emit(SIGNAL('cb'), backend, data) diff --git a/weboob/tools/application/repl.py b/weboob/tools/application/repl.py index f5459fd7..838f02e1 100644 --- a/weboob/tools/application/repl.py +++ b/weboob/tools/application/repl.py @@ -453,11 +453,11 @@ class ReplApplication(Cmd, ConsoleApplication): else: return super(ReplApplication, self).bcall_error_handler(backend, error, backtrace) - def bcall_errors_handler(self, errors): + def bcall_errors_handler(self, errors, ignore=()): if self.interactive: - ConsoleApplication.bcall_errors_handler(self, errors, 'Use "logging debug" option to print backtraces.') + ConsoleApplication.bcall_errors_handler(self, errors, 'Use "logging debug" option to print backtraces.', ignore) else: - ConsoleApplication.bcall_errors_handler(self, errors) + ConsoleApplication.bcall_errors_handler(self, errors, ignore=ignore) # -- options related methods ------------- def _handle_options(self): @@ -998,11 +998,8 @@ class ReplApplication(Cmd, ConsoleApplication): if res: collections.append(res) except CallErrors as errors: - for backend, error, backtrace in errors.errors: - if isinstance(error, CollectionNotFound): - pass - else: - self.bcall_error_handler(backend, error, backtrace) + self.bcall_errors_handler(errors, CollectionNotFound) + if len(collections): # update the path from the collection if possible if len(collections) == 1: @@ -1027,11 +1024,7 @@ class ReplApplication(Cmd, ConsoleApplication): else: objects.append(res) except CallErrors as errors: - for backend, error, backtrace in errors.errors: - if isinstance(error, CollectionNotFound): - pass - else: - self.bcall_error_handler(backend, error, backtrace) + self.bcall_errors_handler(errors, CollectionNotFound) return (objects, collections) @@ -1055,11 +1048,7 @@ class ReplApplication(Cmd, ConsoleApplication): try: self.objects, self.collections = self._fetch_objects(objs=self.COLLECTION_OBJECTS) except CallErrors as errors: - for backend, error, backtrace in errors.errors: - if isinstance(error, CollectionNotFound): - pass - else: - self.bcall_error_handler(backend, error, backtrace) + self.bcall_errors_handler(errors, CollectionNotFound) collections = self.all_collections() for collection in collections: