"""$Id: feed.py 1040 2009-02-15 20:01:32Z sa3ruby $""" __author__ = "Sam Ruby and Mark Pilgrim " __version__ = "$Revision: 1040 $" __copyright__ = "Copyright (c) 2002 Sam Ruby and Mark Pilgrim" from base import validatorBase from validators import * from logging import * from itunes import itunes_channel from extension import extension_feed # # Atom root element # class feed(validatorBase, extension_feed, itunes_channel): def getExpectedAttrNames(self): return [(u'urn:atom-extension:indexing', u'index')] def prevalidate(self): self.links = [] self.validate_optional_attribute((u'urn:atom-extension:indexing', u'index'), yesno) def missingElement(self, params): offset = [self.line - self.dispatcher.locator.getLineNumber(), self.col - self.dispatcher.locator.getColumnNumber()] self.log(MissingElement(params), offset) def validate_metadata(self): if not 'title' in self.children: self.missingElement({"parent":self.name, "element":"title"}) if not 'id' in self.children: self.missingElement({"parent":self.name, "element":"id"}) if not 'updated' in self.children: self.missingElement({"parent":self.name, "element":"updated"}) # complete feeds can only have current=self and no other links if 'fh_complete' in self.children: for link in self.links: if link.rel in link.rfc5005: if link.rel == "current": if link.href not in self.dispatcher.selfURIs: self.log(CurrentNotSelfInCompleteFeed({"rel":link.rel})) else: self.log(FeedRelInCompleteFeed({"rel":link.rel})) # ensure that there is a link rel="self" if self.name != 'source': for link in self.links: if link.rel=='self': break else: offset = [self.line - self.dispatcher.locator.getLineNumber(), self.col - self.dispatcher.locator.getColumnNumber()] self.log(MissingSelf({"parent":self.parent.name, "element":self.name}), offset) types={} archive=False current=False for link in self.links: if link.rel == 'current': current = True if link.rel in ['prev-archive', 'next-archive']: archive = True # attempts to link past the end of the list if link.rel == 'first' and link.href in self.dispatcher.selfURIs: for link2 in self.links: if link2.rel == 'previous': self.log(LinkPastEnd({"self":link.rel, "rel":link2.rel})) if link.rel == 'last' and link.href in self.dispatcher.selfURIs: for link2 in self.links: if link2.rel == 'next': self.log(LinkPastEnd({"self":link.rel, "rel":link2.rel})) # can only have one alternate per type if not link.rel=='alternate': continue if not link.type in types: types[link.type]={} if link.rel in types[link.type]: if link.hreflang in types[link.type][link.rel]: self.log(DuplicateAtomLink({"parent":self.name, "element":"link", "type":link.type, "hreflang":link.hreflang})) else: types[link.type][link.rel] += [link.hreflang] else: types[link.type][link.rel] = [link.hreflang] if 'fh_archive' in self.children: # archives should either have links or be marked complete if not archive and 'fh_complete' not in self.children: self.log(ArchiveIncomplete({})) # archives should have current links if not current and ('fh_complete' not in self.children): self.log(MissingCurrentInArchive({})) if self.itunes: itunes_channel.validate(self) def metadata(self): if 'entry' in self.children: self.log(MisplacedMetadata({"parent":self.name, "element":self.child})) def validate(self): entries = self.children.count('entry') dups = 0 for event in self.dispatcher.loggedEvents: if isinstance(event,DuplicateEntries): dups += event.params.get('msgcount',1) if entries > 9 and entries == dups + 1: self.log(DuplicateIds({})) self.dispatcher.loggedEvents = [event for event in self.dispatcher.loggedEvents if not isinstance(event,DuplicateEntries)] if not 'entry' in self.children: self.validate_metadata() def do_author(self): self.metadata() from author import author return author() def do_category(self): self.metadata() from category import category return category() def do_contributor(self): self.metadata() from author import author return author() def do_generator(self): self.metadata() from generator import generator return generator(), nonblank(), noduplicates() def do_id(self): self.metadata() return canonicaluri(), nows(), noduplicates() def do_icon(self): self.metadata() return nonblank(), nows(), rfc2396(), noduplicates() def do_link(self): self.metadata() from link import link self.links.append(link()) return self.links[-1] def do_logo(self): self.metadata() return nonblank(), nows(), rfc2396(), noduplicates() def do_title(self): self.metadata() from content import textConstruct return textConstruct(), noduplicates() def do_subtitle(self): self.metadata() from content import textConstruct return textConstruct(), noduplicates() def do_rights(self): self.metadata() from content import textConstruct return textConstruct(), noduplicates() def do_updated(self): self.metadata() return rfc3339(), nows(), noduplicates() def do_entry(self): if not 'entry' in self.children: self.validate_metadata() from entry import entry return entry() def do_app_collection(self): from service import collection return collection(), noduplicates()