diff --git a/modules/canalplus/backend.py b/modules/canalplus/backend.py index 4b9491f9553ab130b4d203b7f27a1adc8bdbdb1f..18e7a2c8c1f5c08fdcd7d7b0c634bcd83423ab66 100644 --- a/modules/canalplus/backend.py +++ b/modules/canalplus/backend.py @@ -27,7 +27,7 @@ from weboob.tools.value import Value from .browser import CanalplusBrowser -from .pages import CanalplusVideo +from .video import CanalplusVideo from weboob.capabilities.collection import ICapCollection diff --git a/modules/canalplus/browser.py b/modules/canalplus/browser.py index cdc074af59e91e2bbe84fe1f39a1dc8a82890010..8b78e6b0e60353ec896e86520d550b4972214599 100644 --- a/modules/canalplus/browser.py +++ b/modules/canalplus/browser.py @@ -25,7 +25,8 @@ from weboob.tools.browser import BaseBrowser from weboob.tools.browser.decorators import id2url -from .pages import InitPage, CanalplusVideo, VideoPage +from .pages import InitPage, VideoPage +from .video import CanalplusVideo from weboob.capabilities.collection import Collection, CollectionNotFound @@ -85,9 +86,12 @@ def walk_res(path, collections): if len(path) == 0 or not isinstance(collections, (list, Collection)): return collections i = path[0] - if i not in [collection.title for collection in collections]: - raise CollectionNotFound() + matches = [collection + for collection in collections + if collection.id == i or collection.title == i] + if not len(matches): + raise CollectionNotFound(path) - return walk_res(path[1:], [collection.children for collection in collections if collection.title == i][0]) + return walk_res(path[1:], matches[0]) return walk_res(split_path, collections) diff --git a/modules/canalplus/pages/__init__.py b/modules/canalplus/pages/__init__.py index c4277bc35b415afa72ed9105604069663d1b405c..1f5ee4cb3faedebaca1de6f41ad9e7b8981c39c0 100644 --- a/modules/canalplus/pages/__init__.py +++ b/modules/canalplus/pages/__init__.py @@ -18,7 +18,6 @@ # along with weboob. If not, see . from .initpage import InitPage -from .video import CanalplusVideo from .videopage import VideoPage -__all__ = ['InitPage', 'VideoPage', 'CanalplusVideo'] +__all__ = ['InitPage', 'VideoPage'] diff --git a/modules/canalplus/pages/initpage.py b/modules/canalplus/pages/initpage.py index a235ddb74dc8fd580fac43af7c2d7b0470cbdfb5..1df734210a0c1afee9682e94a172eace35dc5b50 100644 --- a/modules/canalplus/pages/initpage.py +++ b/modules/canalplus/pages/initpage.py @@ -26,24 +26,24 @@ class InitPage(BasePage): - def on_loaded(self): self.collections = [] - - def do(id): - self.browser.location("http://service.canal-plus.com/video/rest/getMEAs/cplus/" + id) + + def do(_id): + self.browser.location("http://service.canal-plus.com/video/rest/getMEAs/cplus/%s" % _id) return self.browser.page.iter_channel() - ### Parse liste des channels + # Parse the list of channels for elem in self.document[2].getchildren(): - coll = Collection() + children = [] for e in elem.getchildren(): if e.tag == "NOM": - coll.title = e.text.strip().encode('utf-8') + _id = e.text.strip() elif e.tag == "SELECTIONS": for select in e: - sub = Collection(title=select[1].text.strip().encode('utf-8')) - sub.id = select[0].text - sub.children = do - coll.appendchild(sub) + sub = Collection(_id=select[0].text, + title=select[1].text.strip(), + fct=do) + children.append(sub) + coll = Collection(_id, children=children) self.collections.append(coll) diff --git a/modules/canalplus/pages/videopage.py b/modules/canalplus/pages/videopage.py index c01aef15d4ddbba80310790605bd8b291d736efb..9e04cb8d86a879fb3bfeca622a6e23000f871953 100644 --- a/modules/canalplus/pages/videopage.py +++ b/modules/canalplus/pages/videopage.py @@ -23,7 +23,7 @@ from weboob.capabilities.base import NotAvailable from weboob.tools.capabilities.thumbnail import Thumbnail from weboob.tools.browser import BasePage -from .video import CanalplusVideo +from ..video import CanalplusVideo __all__ = ['VideoPage'] @@ -78,7 +78,7 @@ def iter_results(self): def iter_channel(self): for vid in self.document.getchildren(): - yield self.parse_video_channel(vid) + yield self.parse_video_channel(vid) def parse_video_channel(self,el): _id = el[0].text diff --git a/modules/canalplus/pages/video.py b/modules/canalplus/video.py similarity index 100% rename from modules/canalplus/pages/video.py rename to modules/canalplus/video.py diff --git a/modules/nova/backend.py b/modules/nova/backend.py index 05e0a39b7eff9dae1e08656b7134a9d101c4a3b1..50892aca754b8f22530052f84534aedda33a2b32 100644 --- a/modules/nova/backend.py +++ b/modules/nova/backend.py @@ -64,7 +64,7 @@ class NovaBackend(BaseBackend, ICapRadio, ICapCollection): def iter_resources(self, split_path): if len(split_path) > 0: - raise CollectionNotFound() + raise CollectionNotFound(split_path) for id in self._RADIOS.iterkeys(): yield self.get_radio(id) diff --git a/modules/ouifm/backend.py b/modules/ouifm/backend.py index 9c68837703e936e620868f81cd1fb97be03b87c6..64a6b392e440b5833ecad7c0107587fb7f3a72d9 100644 --- a/modules/ouifm/backend.py +++ b/modules/ouifm/backend.py @@ -48,7 +48,7 @@ def create_default_browser(self): def iter_resources(self, split_path): if len(split_path) > 0: - raise CollectionNotFound() + raise CollectionNotFound(split_path) for id in self._RADIOS.iterkeys(): yield self.get_radio(id) diff --git a/modules/radiofrance/backend.py b/modules/radiofrance/backend.py index 09c35af0a50a355485cb738b07251765c53c4376..118f9efb81d6952be8199e11aed9d19d976bef26 100644 --- a/modules/radiofrance/backend.py +++ b/modules/radiofrance/backend.py @@ -159,19 +159,20 @@ class RadioFranceBackend(BaseBackend, ICapRadio, ICapCollection): def iter_resources(self, split_path): if len(split_path) == 1 and split_path[0] == 'francebleu': - for id in sorted(self._RADIOS.iterkeys()): - if id.startswith('fb'): - yield self.get_radio(id) + for _id in sorted(self._RADIOS.iterkeys()): + if _id.startswith('fb'): + yield self.get_radio(_id) elif len(split_path) == 0: - for id in sorted(self._RADIOS.iterkeys()): - if not id.startswith('fb'): - yield self.get_radio(id) - yield Collection('francebleu', self.iter_resources('francebleu')) + for _id in sorted(self._RADIOS.iterkeys()): + if not _id.startswith('fb'): + yield self.get_radio(_id) + yield Collection('francebleu', 'France Bleu', + children=self.iter_resources(['francebleu'])) else: - raise CollectionNotFound() + raise CollectionNotFound(split_path) def iter_radios_search(self, pattern): - for radio in self.iter_resources([]): + for radio in self._flatten_resources(self.iter_resources([])): if pattern.lower() in radio.title.lower() or pattern.lower() in radio.description.lower(): yield radio diff --git a/modules/redmine/backend.py b/modules/redmine/backend.py index 7482875f5b6b4c4818a846075bb5c14592bdb6af..e475e7d37cd8fad17cae7ebb7de66a636df7bc2f 100644 --- a/modules/redmine/backend.py +++ b/modules/redmine/backend.py @@ -94,16 +94,17 @@ def get_content_preview(self, content): return self.browser.get_wiki_preview(project, page, content.content) ############# CapCollection ################################################### - def iter_resources(self, path): - if len(path) == 0: - return [Collection(project.id) for project in self.iter_projects()] + def iter_resources(self, split_path): + if len(split_path) == 0: + return [Collection(project.id, project.name, fct=self.iter_issues) + for project in self.iter_projects()] - if len(path) == 1: + if len(split_path) == 1: query = Query() - query.project = unicode(path[0]) + query.project = unicode(split_path[0]) return self.iter_issues(query) - raise CollectionNotFound() + raise CollectionNotFound(split_path) ############# CapBugTracker ################################################### diff --git a/weboob/capabilities/bank.py b/weboob/capabilities/bank.py index 60c4f79f48a5bd7da8995bebc1e2c9d370f248e9..cfdc08a2a3f45963ed8ad2834a14594dd4232a22 100644 --- a/weboob/capabilities/bank.py +++ b/weboob/capabilities/bank.py @@ -76,7 +76,7 @@ def __init__(self, id): class ICapBank(ICapCollection): def iter_resources(self, split_path): if len(split_path) > 0: - raise CollectionNotFound() + raise CollectionNotFound(split_path) return self.iter_accounts() diff --git a/weboob/capabilities/collection.py b/weboob/capabilities/collection.py index 70e467b727a343b86d6527894a588333e3848026..fb398e37e5cd05eb3819a1a64e41448d3e782d03 100644 --- a/weboob/capabilities/collection.py +++ b/weboob/capabilities/collection.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2010-2011 Nicolas Duhamel +# Copyright(C) 2010-2012 Nicolas Duhamel, Laurent Bachelier # # This file is part of weboob. # @@ -21,44 +21,79 @@ __all__ = ['ICapCollection', 'Collection', 'CollectionNotFound'] + class CollectionNotFound(Exception): - def __init__(self, msg=None): - if msg is None: + def __init__(self, split_path=None): + if split_path is not None: + msg = 'Collection not found: %s' % '/'.join(split_path) + else: msg = 'Collection not found' Exception.__init__(self, msg) class Children(object): + """ + Dynamic property of a Collection. + Returns a list, either by calling a function or because + it already has the list. + """ def __get__(self, obj, type=None): - if callable(obj._childrenfct): - return obj._childrenfct(obj.id) - else: - return obj._children + if obj._children is None: + if callable(obj._fct): + obj._children = obj._fct(obj.id) + return obj._children or [] - def __set__(self, obj, value): - obj._childrenfct = value class Collection(object): """ - _childrenfct - _children - appendchild - children return iterator + Collection of objects. + Should provide a way to be filled, either by providing the children + right away, or a function. The function will be called once with the id + as an argument if there were no children provided, but only on demand. + It can be found in a list of objects, it indicantes a "folder" + you can hop into. + id and title should be unicode. """ children = Children() - def __init__(self, title=None, children=None): + def __init__(self, _id=None, title=None, children=None, fct=None): + self.id = _id self.title = title - self._children = children if children else [] - self._childrenfct = None + # It does not make sense to have both at init + assert not (fct is not None and children is not None) + self._children = children + self._fct = fct - def appendchild(self, child): - self._children.append(child) + def __iter__(self): + return iter(self.children) + def __unicode__(self): + if self.title and self.id: + return u'%s (%s)' % (self.id, self.title) + elif self.id: + return u'%s' % self.id + else: + return u'Unknown collection' -class Ressource(object): - pass class ICapCollection(IBaseCap): + def _flatten_resources(self, resources, clean_only=False): + """ + Expand all collections in a list + If clean_only is True, do not expand collections, only remove them. + """ + lst = list() + for resource in resources: + if isinstance(resource, (list, Collection)): + if not clean_only: + lst.extend(self._flatten_resources(resource)) + else: + lst.append(resource) + return lst + def iter_resources(self, split_path): + """ + split_path is a list, either empty (root path) or with one or many + components. + """ raise NotImplementedError() diff --git a/weboob/tools/application/repl.py b/weboob/tools/application/repl.py index 3146f0adc8fe81d45dc92a930316349ebfc2b1b0..e7fe86f1749d5f5122585176f0064e355cb452c1 100644 --- a/weboob/tools/application/repl.py +++ b/weboob/tools/application/repl.py @@ -854,6 +854,14 @@ def do_ls(self, line): for obj in self.objects: if isinstance(obj, CapBaseObject): self.format(obj) + elif isinstance(obj, Collection): + if obj.id and obj.title: + print u'Collection: %s%s%s (%s)' % \ + (self.BOLD, obj.id, self.NC, obj.title) + elif obj.id: + print u'Collection: %s%s%s' % (self.BOLD, obj.id, self.NC) + else: + print obj else: print obj.title @@ -861,13 +869,15 @@ def do_ls(self, line): def do_cd(self, line): """ - cd PATH + cd [PATH] Follow a path. + If empty, return home. """ - line = line.encode('utf-8') - - self.working_path.extend(line) + if not len(line.strip()): + self.working_path.home() + else: + self.working_path.extend(line) objects = self._fetch_objects() if len(objects) == 0: diff --git a/weboob/tools/path.py b/weboob/tools/path.py index 07fa751c407a513ba12d110257d6fc5d809e411b..a148360e68392cafcdb04a8d005458e014221194 100644 --- a/weboob/tools/path.py +++ b/weboob/tools/path.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2010-2011 Nicolas Duhamel +# Copyright(C) 2010-2012 Nicolas Duhamel, Laurent Bachelier # # This file is part of weboob. # @@ -27,6 +27,9 @@ def __init__(self): def extend(self, user_input): + """ + Add a new part to the current path + """ user_input = urllib.quote_plus(user_input) user_input = posixpath.normpath(user_input) @@ -49,8 +52,17 @@ def extend(self, user_input): self._working_path = final_parse def restore(self): + """ + Go to the previous path + """ self._working_path = self._previous + def home(self): + """ + Go to the root + """ + self._previous = self._working_path + self._working_path = [] def get(self): return copy.copy(self._working_path)