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.
This commit is contained in:
Laurent Bachelier 2012-03-11 00:59:35 +01:00
commit e70a125ab9
3 changed files with 44 additions and 22 deletions

View file

@ -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):

View file

@ -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)

View file

@ -893,10 +893,23 @@ class ReplApplication(Cmd, ConsoleApplication):
else:
self.working_path.cd1(line)
collections = [res for backend, res in self.do('get_collection',
collections = []
try:
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]
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:
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()))