From e70a125ab9c7ca7805226e8b71877d29653d49ac Mon Sep 17 00:00:00 2001 From: Laurent Bachelier Date: Sun, 11 Mar 2012 00:59:35 +0100 Subject: [PATCH] Make collection validation more powerful Handle and use exceptions. An example is provided with the redmine backend (not very useful though). If you cd into the project title instead of the id, it is accepted and the path is corrected. --- modules/redmine/backend.py | 21 ++++++++++++--------- weboob/capabilities/collection.py | 17 ++++++++--------- weboob/tools/application/repl.py | 28 ++++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/modules/redmine/backend.py b/modules/redmine/backend.py index d8cd1b0e..0f544214 100644 --- a/modules/redmine/backend.py +++ b/modules/redmine/backend.py @@ -107,15 +107,18 @@ class RedmineBackend(BaseBackend, ICapContent, ICapBugTracker, ICapCollection): raise CollectionNotFound(split_path) - def _is_collection_valid(self, objs, split_path): - if len(split_path) == 0: - return True - if Issue in objs and len(split_path) == 1: - for project in self.browser.iter_projects(): - if split_path[0] in (project['id'], project['name']): - return True - return self.get_project(split_path[0]) is not None - return False + def validate_collection(self, objs, collection): + if len(collection.split_path) == 0: + return + if Issue in objs and len(collection.split_path) == 1: + for project in self.iter_projects(): + if collection.split_path[0] == project.id: + return Collection([project.id], project.name) + # if the project is not found by ID, try again by name + for project in self.iter_projects(): + if collection.split_path[0] == project.name: + return Collection([project.id], project.name) + raise CollectionNotFound(collection.split_path) ############# CapBugTracker ################################################### def _build_project(self, project_dict): diff --git a/weboob/capabilities/collection.py b/weboob/capabilities/collection.py index e85820d0..5742c89d 100644 --- a/weboob/capabilities/collection.py +++ b/weboob/capabilities/collection.py @@ -82,22 +82,21 @@ class ICapCollection(IBaseCap): it should return None. """ collection = Collection(split_path, None, self.name) - if self._is_collection_valid(objs, collection.split_path): - return collection + return self.validate_collection(objs, collection) or collection - def _is_collection_valid(self, objs, split_path): + def validate_collection(self, objs, collection): """ Tests if a collection is valid. For compatibility reasons, and to provide a default way, it checks if the collection has at least one object in it. However, it is not very efficient or exact, and you are encouraged to override this method. + You can replace the collection object entirely by returning a new one. """ # Root - if len(split_path) == 0: - return True + if len(collection.split_path) == 0: + return try: - i = self.iter_resources(objs, split_path) + i = self.iter_resources(objs, collection.split_path) i.next() - return True - except (StopIteration, CollectionNotFound): - return False + except StopIteration: + raise CollectionNotFound(collection.split_path) diff --git a/weboob/tools/application/repl.py b/weboob/tools/application/repl.py index c8897a03..09789b98 100644 --- a/weboob/tools/application/repl.py +++ b/weboob/tools/application/repl.py @@ -893,10 +893,23 @@ class ReplApplication(Cmd, ConsoleApplication): else: self.working_path.cd1(line) - collections = [res for backend, res in self.do('get_collection', - objs=self.COLLECTION_OBJECTS, split_path=self.working_path.get(), - caps=ICapCollection) if res is not None] + collections = [] + try: + for backend, res in self.do('get_collection', + objs=self.COLLECTION_OBJECTS, split_path=self.working_path.get(), + caps=ICapCollection): + if res: + collections.append(res) + except CallErrors, errors: + for backend, error, backtrace in errors.errors: + if isinstance(error, CollectionNotFound): + pass + else: + self.bcall_error_handler(backend, error, backtrace) if len(collections): + # update the path from the collection if possible + if len(collections) == 1: + self.working_path.split_path = collections[0].split_path self._change_prompt() else: print >>sys.stderr, u"Path: %s not found" % unicode(self.working_path) @@ -933,7 +946,14 @@ class ReplApplication(Cmd, ConsoleApplication): offs = len(mline) - len(text) if len(self.collections) == 0: - self.objects, self.collections = self._fetch_objects(objs=self.COLLECTION_OBJECTS) + try: + self.objects, self.collections = self._fetch_objects(objs=self.COLLECTION_OBJECTS) + except CallErrors, errors: + for backend, error, backtrace in errors.errors: + if isinstance(error, CollectionNotFound): + pass + else: + self.bcall_error_handler(backend, error, backtrace) for collection in self.collections: directories.add(collection.id.encode(sys.stdout.encoding or locale.getpreferredencoding()))