display a message when more results are available (closes #1038)

This commit is contained in:
Romain Bignon 2013-07-27 21:58:50 +02:00
commit 46d9acd37e
6 changed files with 84 additions and 57 deletions

View file

@ -574,22 +574,18 @@ class Cineoob(ReplApplication):
if dest is None: if dest is None:
dest = '%s' % _id dest = '%s' % _id
try: for backend, buf in self.do('get_subtitle_file', _id, backends=backend_name, caps=ICapSubtitle):
for backend, buf in self.do('get_subtitle_file', _id, backends=backend_name, caps=ICapSubtitle): if buf:
if buf: if dest == '-':
if dest == '-': print buf
print buf else:
else: try:
try: with open(dest, 'w') as f:
with open(dest, 'w') as f: f.write(buf)
f.write(buf) except IOError as e:
except IOError as e: print >>sys.stderr, 'Unable to write file in "%s": %s' % (dest, e)
print >>sys.stderr, 'Unable to write file in "%s": %s' % (dest, e) return 1
return 1 return
return
except CallErrors as errors:
for backend, error, backtrace in errors:
self.bcall_error_handler(backend, error, backtrace)
print >>sys.stderr, 'Subtitle "%s" not found' % id print >>sys.stderr, 'Subtitle "%s" not found' % id
return 3 return 3

View file

@ -56,10 +56,12 @@ class ResultsConditionError(Exception):
class BackendsCall(object): class BackendsCall(object):
def __init__(self, backends, condition, function, *args, **kwargs): def __init__(self, backends, condition, function, *args, **kwargs):
""" """
@param backends list of backends to call. :param backends: List of backends to call
@param condition a IResultsCondition object. Can be None. :type backends: list[:class:`BaseBackend`]
@param function backends' method name, or callable object. :param condition: Condition applied on results (can be None)
@param args, kwargs arguments given to called functions. :type condition: :class:`IResultsCondition`
:param function: backends' method name, or callable object.
:type function: :class:`str` or :class:`callable`
""" """
self.logger = getLogger('bcall') self.logger = getLogger('bcall')
# Store if a backend is finished # Store if a backend is finished

View file

@ -37,6 +37,9 @@ from weboob.tools.misc import to_unicode
__all__ = ['BaseApplication'] __all__ = ['BaseApplication']
class MoreResultsAvailable(Exception):
pass
class ApplicationStorage(object): class ApplicationStorage(object):
def __init__(self, name, storage): def __init__(self, name, storage):
self.name = name self.name = name
@ -164,10 +167,13 @@ class BaseApplication(object):
""" """
Create a storage object. Create a storage object.
@param path [str] an optional specific path. :param path: An optional specific path
@param klass [IStorage] what klass to instance. :type path: :class:`str`
@param localonly [bool] if True, do not set it on the Weboob object. :param klass: What class to instance
@return a IStorage object :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: if klass is None:
from weboob.tools.storage import StandardStorage from weboob.tools.storage import StandardStorage
@ -191,9 +197,11 @@ class BaseApplication(object):
""" """
Load a configuration file and get his object. Load a configuration file and get his object.
@param path [str] an optional specific path. :param path: An optional specific path
@param klass [IConfig] what klass to instance. :type path: :class:`str`
@return a IConfig object :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: if klass is None:
from weboob.tools.config.iniconfig import INIConfig from weboob.tools.config.iniconfig import INIConfig
@ -242,7 +250,7 @@ class BaseApplication(object):
def _do_complete_iter(self, backend, count, fields, res): def _do_complete_iter(self, backend, count, fields, res):
for i, sub in enumerate(res): for i, sub in enumerate(res):
if count and i == count: if count and i == count:
break raise MoreResultsAvailable()
sub = self._do_complete_obj(backend, fields, sub) sub = self._do_complete_obj(backend, fields, sub)
yield sub yield sub
@ -264,18 +272,39 @@ class BaseApplication(object):
This method can be overrided to support more exceptions types. 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) print >>sys.stderr, u'Error(%s): %s' % (backend.name, error)
if logging.root.level == logging.DEBUG: if logging.root.level == logging.DEBUG:
print >>sys.stderr, backtrace 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. 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: for backend, error, backtrace in errors.errors:
self.bcall_error_handler(backend, error, backtrace) if isinstance(error, ignore):
if logging.root.level != logging.DEBUG: continue
print >>sys.stderr, 'Use --debug option to print backtraces.' 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): def parse_args(self, args):
self.options, args = self._parser.parse_args(args) self.options, args = self._parser.parse_args(args)
@ -372,6 +401,7 @@ class BaseApplication(object):
a call to sys.exit(). a call to sys.exit().
For example: For example:
>>> from weboob.application.myapplication import MyApplication >>> from weboob.application.myapplication import MyApplication
>>> MyApplication.run() >>> MyApplication.run()
""" """

View file

@ -37,7 +37,7 @@ from weboob.tools.browser import BrowserUnavailable, BrowserIncorrectPassword, B
from weboob.tools.value import Value, ValueBool, ValueFloat, ValueInt from weboob.tools.value import Value, ValueBool, ValueFloat, ValueInt
from weboob.tools.misc import to_unicode from weboob.tools.misc import to_unicode
from .base import BaseApplication from .base import BaseApplication, MoreResultsAvailable
__all__ = ['ConsoleApplication', 'BackendNotGiven'] __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) print >>sys.stderr, u' %s please contact: %s <%s>' % (' ' * len(backend.name), backend.MAINTAINER, backend.EMAIL)
elif isinstance(error, UserError): elif isinstance(error, UserError):
print >>sys.stderr, u'Error(%s): %s' % (backend.name, to_unicode(error)) 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): elif isinstance(error, SSLError):
print >>sys.stderr, u'FATAL(%s): ' % backend.name + self.BOLD + '/!\ SERVER CERTIFICATE IS INVALID /!\\' + self.NC print >>sys.stderr, u'FATAL(%s): ' % backend.name + self.BOLD + '/!\ SERVER CERTIFICATE IS INVALID /!\\' + self.NC
else: else:
@ -519,14 +521,21 @@ class ConsoleApplication(BaseApplication):
else: else:
return True 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. Handler for the CallErrors exception.
""" """
ask_debug_mode = False ask_debug_mode = False
more_results = set()
for backend, error, backtrace in errors.errors: 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 ask_debug_mode = True
if ask_debug_mode: if ask_debug_mode:
print >>sys.stderr, debugmsg print >>sys.stderr, debugmsg
elif len(more_results) > 0:
print >>sys.stderr, 'Hint: There are more results available for %s' % (', '.join(more_results))

View file

@ -37,7 +37,7 @@ from weboob.tools.value import ValueInt, ValueBool, ValueBackendPassword
from weboob.tools.misc import to_unicode from weboob.tools.misc import to_unicode
from weboob.capabilities import UserError from weboob.capabilities import UserError
from ..base import BaseApplication from ..base import BaseApplication, MoreResultsAvailable
__all__ = ['QtApplication', 'QtMainWindow', 'QtDo', 'HTMLDelegate'] __all__ = ['QtApplication', 'QtMainWindow', 'QtDo', 'HTMLDelegate']
@ -201,6 +201,10 @@ class QtDo(QObject):
self.process.callback_thread(self.thread_cb, self.thread_eb) self.process.callback_thread(self.thread_cb, self.thread_eb)
def default_eb(self, backend, error, backtrace): def default_eb(self, backend, error, backtrace):
if isinstance(error, MoreResultsAvailable):
# This is not an error, ignore.
return
msg = unicode(error) msg = unicode(error)
if isinstance(error, BrowserIncorrectPassword): if isinstance(error, BrowserIncorrectPassword):
if not msg: if not msg:
@ -247,9 +251,6 @@ class QtDo(QObject):
def local_eb(self, backend, error, backtrace): def local_eb(self, backend, error, backtrace):
self.eb(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): def thread_cb(self, backend, data):
self.emit(SIGNAL('cb'), backend, data) self.emit(SIGNAL('cb'), backend, data)

View file

@ -453,11 +453,11 @@ class ReplApplication(Cmd, ConsoleApplication):
else: else:
return super(ReplApplication, self).bcall_error_handler(backend, error, backtrace) 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: 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: else:
ConsoleApplication.bcall_errors_handler(self, errors) ConsoleApplication.bcall_errors_handler(self, errors, ignore=ignore)
# -- options related methods ------------- # -- options related methods -------------
def _handle_options(self): def _handle_options(self):
@ -998,11 +998,8 @@ class ReplApplication(Cmd, ConsoleApplication):
if res: if res:
collections.append(res) collections.append(res)
except CallErrors as errors: except CallErrors as errors:
for backend, error, backtrace in errors.errors: self.bcall_errors_handler(errors, CollectionNotFound)
if isinstance(error, CollectionNotFound):
pass
else:
self.bcall_error_handler(backend, error, backtrace)
if len(collections): if len(collections):
# update the path from the collection if possible # update the path from the collection if possible
if len(collections) == 1: if len(collections) == 1:
@ -1027,11 +1024,7 @@ class ReplApplication(Cmd, ConsoleApplication):
else: else:
objects.append(res) objects.append(res)
except CallErrors as errors: except CallErrors as errors:
for backend, error, backtrace in errors.errors: self.bcall_errors_handler(errors, CollectionNotFound)
if isinstance(error, CollectionNotFound):
pass
else:
self.bcall_error_handler(backend, error, backtrace)
return (objects, collections) return (objects, collections)
@ -1055,11 +1048,7 @@ class ReplApplication(Cmd, ConsoleApplication):
try: try:
self.objects, self.collections = self._fetch_objects(objs=self.COLLECTION_OBJECTS) self.objects, self.collections = self._fetch_objects(objs=self.COLLECTION_OBJECTS)
except CallErrors as errors: except CallErrors as errors:
for backend, error, backtrace in errors.errors: self.bcall_errors_handler(errors, CollectionNotFound)
if isinstance(error, CollectionNotFound):
pass
else:
self.bcall_error_handler(backend, error, backtrace)
collections = self.all_collections() collections = self.all_collections()
for collection in collections: for collection in collections: