Rough in HTMLTMPL support
This commit is contained in:
parent
70180abcb1
commit
d17d509adc
1
.bzrignore
Normal file
1
.bzrignore
Normal file
@ -0,0 +1 @@
|
||||
*.tmplc
|
1480
planet/htmltmpl.py
Normal file
1480
planet/htmltmpl.py
Normal file
File diff suppressed because it is too large
Load Diff
23
planet/shell/__init__.py
Normal file
23
planet/shell/__init__.py
Normal file
@ -0,0 +1,23 @@
|
||||
import planet
|
||||
import os
|
||||
|
||||
def run(template_file, doc):
|
||||
""" select a template module based on file extension and execute it """
|
||||
log = planet.getLogger(planet.config.log_level())
|
||||
|
||||
for template_dir in planet.config.template_directories():
|
||||
template_resolved = os.path.join(template_dir, template_file)
|
||||
if os.path.exists(template_resolved): break
|
||||
else:
|
||||
return log.error("Unable to locate template %s", template_file)
|
||||
|
||||
base,ext = os.path.splitext(os.path.basename(template_resolved))
|
||||
try:
|
||||
module = __import__('planet/shell/' + ext[1:])
|
||||
except:
|
||||
return log.error("Skipping template %s", template_resolved)
|
||||
|
||||
log.info("Processing template %s", template_resolved)
|
||||
output_dir = planet.config.output_dir()
|
||||
output_file = os.path.join(output_dir, base)
|
||||
module.run(template_resolved, doc, output_file)
|
190
planet/shell/tmpl.py
Normal file
190
planet/shell/tmpl.py
Normal file
@ -0,0 +1,190 @@
|
||||
from xml.sax.saxutils import escape
|
||||
import sgmllib, time, os, sys
|
||||
from planet import config, feedparser, htmltmpl
|
||||
|
||||
class stripHtml(sgmllib.SGMLParser):
|
||||
"remove all tags from the data"
|
||||
def __init__(self, data):
|
||||
sgmllib.SGMLParser.__init__(self)
|
||||
self.result=''
|
||||
if isinstance(data, str):
|
||||
try:
|
||||
self.feed(data.decode('utf-8'))
|
||||
except:
|
||||
self.feed(data)
|
||||
else:
|
||||
self.feed(data)
|
||||
self.close()
|
||||
def __str__(self):
|
||||
if isinstance(self.result, unicode):
|
||||
return self.result.encode('utf-8')
|
||||
return self.result
|
||||
def handle_entityref(self, ref):
|
||||
import htmlentitydefs
|
||||
if ref in htmlentitydefs.entitydefs:
|
||||
ref=htmlentitydefs.entitydefs[ref]
|
||||
if len(ref)==1:
|
||||
self.result+=unichr(ord(ref))
|
||||
elif ref.startswith('&#') and ref.endswith(';'):
|
||||
self.handle_charref(ref[2:-1])
|
||||
else:
|
||||
self.result+='&%s;' % ref
|
||||
else:
|
||||
self.result+='&%s;' % ref
|
||||
def handle_charref(self, ref):
|
||||
try:
|
||||
if ref.startswith('x'):
|
||||
self.result+=unichr(int(ref[1:],16))
|
||||
else:
|
||||
self.result+=unichr(int(ref))
|
||||
except:
|
||||
self.result+='&#%s;' % ref
|
||||
def handle_data(self, data):
|
||||
if data: self.result+=data
|
||||
|
||||
# Data format mappers
|
||||
|
||||
def String(value):
|
||||
if isinstance(value, unicode): return value.encode('utf-8')
|
||||
return value
|
||||
|
||||
def Plain(value):
|
||||
return str(stripHtml(value))
|
||||
|
||||
def PlanetDate(value):
|
||||
return time.strftime(config.date_format(), value)
|
||||
|
||||
def Rfc822(value):
|
||||
return time.strftime("%a, %d %b %Y %H:%M:%S +0000", value)
|
||||
|
||||
def Rfc3399(value):
|
||||
return time.strftime("%Y-%m-%dT%H:%M:%S+00:00", value)
|
||||
|
||||
# Map from FeedParser path to Planet tmpl names
|
||||
Base = [
|
||||
['author', String, 'author'],
|
||||
['author_name', String, 'author_detail', 'name'],
|
||||
['feed', String, 'links', {'rel':'self'}, 'href'],
|
||||
['generator', String, 'generator'],
|
||||
['id', String, 'id'],
|
||||
['icon', String, 'icon'],
|
||||
['last_updated_822', Rfc822, 'updated_parsed'],
|
||||
['last_updated_iso', Rfc3399, 'updated_parsed'],
|
||||
['last_updated', PlanetDate, 'updated_parsed'],
|
||||
['logo', String, 'logo'],
|
||||
['rights', String, 'rights_detail', 'value'],
|
||||
['subtitle', String, 'subtitle_detail', 'value'],
|
||||
['title', String, 'title_detail', 'value'],
|
||||
['title_plain', Plain, 'title_detail', 'value'],
|
||||
]
|
||||
|
||||
# ? new_date, new_channel
|
||||
Items = [
|
||||
['author', String, 'author'],
|
||||
['author_email', String, 'author_detail', 'email'],
|
||||
['author_name', String, 'author_detail', 'name'],
|
||||
['author_uri', String, 'author_detail', 'href'],
|
||||
['content_language', String, 'content', 0, 'language'],
|
||||
['content', String, 'summary_detail', 'value'],
|
||||
['content', String, 'content', 0, 'value'],
|
||||
['date', PlanetDate, 'published_parsed'],
|
||||
['date', PlanetDate, 'updated_parsed'],
|
||||
['date_822', Rfc822, 'published_parsed'],
|
||||
['date_822', Rfc822, 'updated_parsed'],
|
||||
['date_iso', Rfc3399, 'published_parsed'],
|
||||
['date_iso', Rfc3399, 'updated_parsed'],
|
||||
['id', String, 'id'],
|
||||
['link', String, 'links', {'rel': 'alternate'}, 'href'],
|
||||
['rights', String, 'rights_detail', 'value'],
|
||||
['title_language', String, 'title_detail', 'language'],
|
||||
['title_plain', Plain, 'title_detail', 'value'],
|
||||
['title', String, 'title_detail', 'value'],
|
||||
['summary_language', String, 'summary_detail', 'language'],
|
||||
['updated', PlanetDate, 'updated_parsed'],
|
||||
['updated_822', Rfc822, 'updated_parsed'],
|
||||
['updated_iso', Rfc3399, 'updated_parsed'],
|
||||
['published', PlanetDate, 'published_parsed'],
|
||||
['published_822', Rfc822, 'published_parsed'],
|
||||
['published_iso', Rfc3399, 'published_parsed'],
|
||||
]
|
||||
|
||||
Channels = [
|
||||
['url', None],
|
||||
['link', None],
|
||||
['message', None],
|
||||
['title_plain', None],
|
||||
['name', None],
|
||||
]
|
||||
|
||||
# Add additional rules for source information
|
||||
for rule in Base:
|
||||
Items.append(['channel_'+rule[0], rule[1], 'source'] + rule[2:])
|
||||
|
||||
def tmpl_mapper(source, rules):
|
||||
"Apply specified rules to the source, and return a template dictionary"
|
||||
output = {}
|
||||
|
||||
for rule in rules:
|
||||
node = source
|
||||
for path in rule[2:]:
|
||||
if isinstance(path, str) and path in node:
|
||||
if path == 'value' and node.get('type','')=='text/plain':
|
||||
node['value'] = escape(node['value'])
|
||||
node['type'] = 'text/html'
|
||||
node = node[path]
|
||||
elif isinstance(path, int):
|
||||
node = node[path]
|
||||
elif isinstance(path, dict):
|
||||
for test in node:
|
||||
for key, value in path.items():
|
||||
if test.get(key,None) != value: break
|
||||
else:
|
||||
node = test
|
||||
break
|
||||
else:
|
||||
break
|
||||
else:
|
||||
break
|
||||
else:
|
||||
if node: output[rule[0]] = rule[1](node)
|
||||
|
||||
# copy over all planet namespaced elements from parent source
|
||||
for name,value in source.items():
|
||||
if name.startswith('planet_'):
|
||||
output[name[7:]] = String(value)
|
||||
|
||||
# copy over all planet namespaced elements from child source element
|
||||
if 'source' in source:
|
||||
for name,value in source.source.items():
|
||||
if name.startswith('planet_'):
|
||||
output['channel_' + name[7:]] = String(value)
|
||||
|
||||
return output
|
||||
|
||||
def template_info(source):
|
||||
""" get template information from a feedparser output """
|
||||
data=feedparser.parse(source)
|
||||
output = {'Channels': [], 'Items': []}
|
||||
output['Channels'].append(tmpl_mapper(data.feed, Base))
|
||||
for entry in data.entries:
|
||||
output['Items'].append(tmpl_mapper(entry, Items))
|
||||
return output
|
||||
|
||||
def run(script, doc, output_file=None):
|
||||
""" process an HTMLTMPL file """
|
||||
manager = htmltmpl.TemplateManager()
|
||||
template = manager.prepare(script)
|
||||
tp = htmltmpl.TemplateProcessor(html_escape=0)
|
||||
for key,value in template_info(doc).items():
|
||||
tp.set(key, value)
|
||||
output = open(output_file, "w")
|
||||
output.write(tp.process(template))
|
||||
output.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.path.insert(0, os.path.split(sys.path[0])[0])
|
||||
|
||||
for test in sys.argv[1:]:
|
||||
from pprint import pprint
|
||||
pprint(template_info('/home/rubys/bzr/venus/tests/data/filter/tmpl/'+test))
|
||||
|
34
planet/shell/xslt.py
Normal file
34
planet/shell/xslt.py
Normal file
@ -0,0 +1,34 @@
|
||||
import os
|
||||
|
||||
def run(script, doc, output_file=None):
|
||||
""" process an XSLT stylesheet """
|
||||
|
||||
try:
|
||||
# if available, use the python interface to libxslt
|
||||
import libxml2
|
||||
import libxslt
|
||||
dom = libxml2.parseDoc(doc)
|
||||
docfile = None
|
||||
except:
|
||||
# otherwise, use the command line interface
|
||||
dom = None
|
||||
import warnings
|
||||
warnings.simplefilter('ignore', RuntimeWarning)
|
||||
docfile = os.tmpnam()
|
||||
file = open(docfile,'w')
|
||||
file.write(doc)
|
||||
file.close()
|
||||
|
||||
# do it
|
||||
if dom:
|
||||
styledoc = libxml2.parseFile(script)
|
||||
style = libxslt.parseStylesheetDoc(styledoc)
|
||||
result = style.applyStylesheet(dom, None)
|
||||
style.saveResultToFilename(output_file, result, 0)
|
||||
style.freeStylesheet()
|
||||
result.freeDoc()
|
||||
else:
|
||||
os.system('xsltproc %s %s > %s' % (script, docfile, output_file))
|
||||
|
||||
if dom: dom.freeDoc()
|
||||
if docfile: os.unlink(docfile)
|
@ -1,7 +1,7 @@
|
||||
""" Splice together a planet from a cache of feed entries """
|
||||
import glob, os, time, shutil
|
||||
from xml.dom import minidom
|
||||
import planet, config, feedparser, reconstitute
|
||||
import planet, config, feedparser, reconstitute, shell
|
||||
from reconstitute import createTextElement, date
|
||||
from spider import filename
|
||||
|
||||
@ -57,53 +57,9 @@ def apply(doc):
|
||||
if not os.path.exists(output_dir): os.makedirs(output_dir)
|
||||
log = planet.getLogger(config.log_level())
|
||||
|
||||
try:
|
||||
# if available, use the python interface to libxslt
|
||||
import libxml2
|
||||
import libxslt
|
||||
dom = libxml2.parseDoc(doc)
|
||||
docfile = None
|
||||
except:
|
||||
# otherwise, use the command line interface
|
||||
dom = None
|
||||
import warnings
|
||||
warnings.simplefilter('ignore', RuntimeWarning)
|
||||
docfile = os.tmpnam()
|
||||
file = open(docfile,'w')
|
||||
file.write(doc)
|
||||
file.close()
|
||||
|
||||
# Go-go-gadget-template
|
||||
for template_file in config.template_files():
|
||||
for template_dir in config.template_directories():
|
||||
template_resolved = os.path.join(template_dir, template_file)
|
||||
if os.path.exists(template_resolved): break
|
||||
else:
|
||||
log.error("Unable to locate template %s", template_file)
|
||||
continue
|
||||
|
||||
base,ext = os.path.splitext(os.path.basename(template_resolved))
|
||||
if ext != '.xslt':
|
||||
log.warning("Skipping template %s", template_resolved)
|
||||
continue
|
||||
|
||||
log.info("Processing template %s", template_resolved)
|
||||
output_file = os.path.join(output_dir, base)
|
||||
if dom:
|
||||
styledoc = libxml2.parseFile(template_resolved)
|
||||
style = libxslt.parseStylesheetDoc(styledoc)
|
||||
result = style.applyStylesheet(dom, None)
|
||||
log.info("Writing %s", output_file)
|
||||
style.saveResultToFilename(output_file, result, 0)
|
||||
style.freeStylesheet()
|
||||
result.freeDoc()
|
||||
else:
|
||||
log.info("Writing %s", output_file)
|
||||
os.system('xsltproc %s %s > %s' %
|
||||
(template_resolved, docfile, output_file))
|
||||
|
||||
if dom: dom.freeDoc()
|
||||
if docfile: os.unlink(docfile)
|
||||
shell.run(template_file, doc)
|
||||
|
||||
# Process bill of materials
|
||||
for copy_file in config.bill_of_materials():
|
||||
|
13
tests/data/filter/tmpl/author_email.xml
Normal file
13
tests/data/filter/tmpl/author_email.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
Description: author name
|
||||
Expect: Items[0]['author'] == 'john@example.com' and Items[0]['author_email'] == 'john@example.com'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<author>
|
||||
<email>john@example.com</email>
|
||||
</author>
|
||||
</entry>
|
||||
</feed>
|
||||
|
13
tests/data/filter/tmpl/author_name.xml
Normal file
13
tests/data/filter/tmpl/author_name.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
Description: author name
|
||||
Expect: Items[0]['author_name'] == 'John Doe' and Items[0]['author'] == 'John Doe'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<author>
|
||||
<name>John Doe</name>
|
||||
</author>
|
||||
</entry>
|
||||
</feed>
|
||||
|
13
tests/data/filter/tmpl/author_uri.xml
Normal file
13
tests/data/filter/tmpl/author_uri.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
Description: author name
|
||||
Expect: Items[0]['author_uri'] == 'http://example.com/~john/'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<author>
|
||||
<uri>http://example.com/~john/</uri>
|
||||
</author>
|
||||
</entry>
|
||||
</feed>
|
||||
|
10
tests/data/filter/tmpl/content_html.xml
Normal file
10
tests/data/filter/tmpl/content_html.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<!--
|
||||
Description: entity encoded html content
|
||||
Expect: Items[0]['content'] == 'Détente'
|
||||
-->
|
||||
|
||||
<feed xmns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<content type="html">D&eacute;tente</content>
|
||||
</entry>
|
||||
</feed>
|
10
tests/data/filter/tmpl/content_lang.xml
Normal file
10
tests/data/filter/tmpl/content_lang.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<!--
|
||||
Description: content value
|
||||
Expect: Items[0]['content'] == 'foo' and Items[0]['content_language'] == 'en-us'
|
||||
-->
|
||||
|
||||
<feed xmns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<content xml:lang="en-us">foo</content>
|
||||
</entry>
|
||||
</feed>
|
10
tests/data/filter/tmpl/content_text.xml
Normal file
10
tests/data/filter/tmpl/content_text.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<!--
|
||||
Description: plain text content
|
||||
Expect: Items[0]['content'] == 'AT&T'
|
||||
-->
|
||||
|
||||
<feed xmns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<content type="text">AT&T</content>
|
||||
</entry>
|
||||
</feed>
|
13
tests/data/filter/tmpl/content_xhtml.xml
Normal file
13
tests/data/filter/tmpl/content_xhtml.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
Description: xhtml content
|
||||
Expect: Items[0]['content'] == 'A <b>very</b> bad day'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<content type="xhtml">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">A <b>very</b> bad day</div>
|
||||
</content>
|
||||
</entry>
|
||||
</feed>
|
||||
|
11
tests/data/filter/tmpl/id.xml
Normal file
11
tests/data/filter/tmpl/id.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<!--
|
||||
Description: id
|
||||
Expect: Items[0]['id'] == 'http://example.com/1'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<id>http://example.com/1</id>
|
||||
</entry>
|
||||
</feed>
|
||||
|
13
tests/data/filter/tmpl/id_only_content.xml
Normal file
13
tests/data/filter/tmpl/id_only_content.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
Description: id generated from content
|
||||
Expect: Items[0]['content'] == 'content'
|
||||
-->
|
||||
|
||||
<rss xml:base="http://example.com/">
|
||||
<channel>
|
||||
<item xmlns:content="http://purl.org/rss/1.0/modules/content/">
|
||||
<content:encoded>content</content>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
|
13
tests/data/filter/tmpl/id_only_description.xml
Normal file
13
tests/data/filter/tmpl/id_only_description.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
Description: id generated from description
|
||||
Expect: Items[0]['content'] == 'description'
|
||||
-->
|
||||
|
||||
<rss xml:base="http://example.com/">
|
||||
<channel>
|
||||
<item>
|
||||
<description>description</description>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
|
13
tests/data/filter/tmpl/id_only_link.xml
Normal file
13
tests/data/filter/tmpl/id_only_link.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
Description: id generated from link
|
||||
Expect: Items[0]['link'] == 'http://example.com/1'
|
||||
-->
|
||||
|
||||
<rss>
|
||||
<channel>
|
||||
<item>
|
||||
<link>http://example.com/1</link>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
|
13
tests/data/filter/tmpl/id_only_title.xml
Normal file
13
tests/data/filter/tmpl/id_only_title.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
Description: id generated from title
|
||||
Expect: Items[0]['title'] == 'title' and Items[0]['title_plain'] == 'title'
|
||||
-->
|
||||
|
||||
<rss xml:base="http://example.com/">
|
||||
<channel>
|
||||
<item>
|
||||
<title>title</title>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
|
11
tests/data/filter/tmpl/link_href.xml
Normal file
11
tests/data/filter/tmpl/link_href.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<!--
|
||||
Description: link relationship
|
||||
Expect: Items[0]['link'] == 'http://example.com/1'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<link href="http://example.com/1"/>
|
||||
</entry>
|
||||
</feed>
|
||||
|
11
tests/data/filter/tmpl/link_rel.xml
Normal file
11
tests/data/filter/tmpl/link_rel.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<!--
|
||||
Description: link relationship
|
||||
Expect: Items[0]['link'] == 'http://example.com/1'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<link href="http://example.com/1"/>
|
||||
</entry>
|
||||
</feed>
|
||||
|
11
tests/data/filter/tmpl/link_type.xml
Normal file
11
tests/data/filter/tmpl/link_type.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<!--
|
||||
Description: link relationship
|
||||
Expect: Items[0]['link'] == 'http://example.com/1'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<link href="http://example.com/1"/>
|
||||
</entry>
|
||||
</feed>
|
||||
|
14
tests/data/filter/tmpl/planet_name.xml
Normal file
14
tests/data/filter/tmpl/planet_name.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Description: id
|
||||
Expect: Channels[0]['name'] == 'foo'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<planet:name>foo</planet:name>
|
||||
<entry>
|
||||
<source>
|
||||
<planet:name>foo</planet:name>
|
||||
</source>
|
||||
</entry>
|
||||
</feed>
|
||||
|
11
tests/data/filter/tmpl/published.xml
Normal file
11
tests/data/filter/tmpl/published.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<!--
|
||||
Description: published, rollover past midnight on feb 28 in leap year
|
||||
Expect: Items[0]['published_iso'] == '2004-02-29T02:14:55+00:00' and Items[0]['published_822'] == 'Sun, 29 Feb 2004 02:14:55 +0000' and Items[0]['published'] == 'February 29, 2004 02:14 AM'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<published>2004-02-28T18:14:55-08:00</published>
|
||||
</entry>
|
||||
</feed>
|
||||
|
11
tests/data/filter/tmpl/rights.xml
Normal file
11
tests/data/filter/tmpl/rights.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<!--
|
||||
Description: rights
|
||||
Expect: Items[0]['rights'] == '© 2006'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<rights type="html">&copy; 2006</rights>
|
||||
</entry>
|
||||
</feed>
|
||||
|
18
tests/data/filter/tmpl/source_author.xml
Normal file
18
tests/data/filter/tmpl/source_author.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<!--
|
||||
Description: source author
|
||||
Expect: Channels[0]['author'] == 'John Doe' and Channels[0]['author_name'] == 'John Doe' and Items[0]['channel_author'] == 'John Doe' and Items[0]['channel_author_name'] == 'John Doe'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<author>
|
||||
<name>John Doe</name>
|
||||
</author>
|
||||
<entry>
|
||||
<source>
|
||||
<author>
|
||||
<name>John Doe</name>
|
||||
</author>
|
||||
</source>
|
||||
</entry>
|
||||
</feed>
|
||||
|
14
tests/data/filter/tmpl/source_icon.xml
Normal file
14
tests/data/filter/tmpl/source_icon.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Description: source icon
|
||||
Expect: Channels[0]['icon'] == 'http://www.example.com/favicon.ico' and Items[0]['channel_icon'] == 'http://www.example.com/favicon.ico'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<icon>http://www.example.com/favicon.ico</icon>
|
||||
<entry>
|
||||
<source>
|
||||
<icon>http://www.example.com/favicon.ico</icon>
|
||||
</source>
|
||||
</entry>
|
||||
</feed>
|
||||
|
14
tests/data/filter/tmpl/source_id.xml
Normal file
14
tests/data/filter/tmpl/source_id.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Description: source id
|
||||
Expect: Channels[0]['id'] == 'http://example.com/' and Items[0]['channel_id'] == 'http://example.com/'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<id>http://example.com/</id>
|
||||
<entry>
|
||||
<source>
|
||||
<id>http://example.com/</id>
|
||||
</source>
|
||||
</entry>
|
||||
</feed>
|
||||
|
14
tests/data/filter/tmpl/source_logo.xml
Normal file
14
tests/data/filter/tmpl/source_logo.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Description: source logo
|
||||
Expect: Channels[0]['logo'] == 'http://www.example.com/logo.jpg' and Items[0]['channel_logo'] == 'http://www.example.com/logo.jpg'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<logo>http://www.example.com/logo.jpg</logo>
|
||||
<entry>
|
||||
<source>
|
||||
<logo>http://www.example.com/logo.jpg</logo>
|
||||
</source>
|
||||
</entry>
|
||||
</feed>
|
||||
|
14
tests/data/filter/tmpl/source_planet_name.xml
Normal file
14
tests/data/filter/tmpl/source_planet_name.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Description: id
|
||||
Expect: Channels[0]['name'] == 'foo' and Items[0]['channel_name'] == 'foo'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<planet:name>foo</planet:name>
|
||||
<entry>
|
||||
<source>
|
||||
<planet:name>foo</planet:name>
|
||||
</source>
|
||||
</entry>
|
||||
</feed>
|
||||
|
14
tests/data/filter/tmpl/source_rights.xml
Normal file
14
tests/data/filter/tmpl/source_rights.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Description: source rights
|
||||
Expect: Channels[0]['rights'] == '© 2006' and Items[0]['channel_rights'] == '© 2006'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<rights type="html">&copy; 2006</rights>
|
||||
<entry>
|
||||
<source>
|
||||
<rights type="html">&copy; 2006</rights>
|
||||
</source>
|
||||
</entry>
|
||||
</feed>
|
||||
|
14
tests/data/filter/tmpl/source_subtitle.xml
Normal file
14
tests/data/filter/tmpl/source_subtitle.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Description: source subtitle
|
||||
Expect: Channels[0]['subtitle'] == 'snarky phrase' and Items[0]['channel_subtitle'] == 'snarky phrase'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<subtitle>snarky phrase</subtitle>
|
||||
<entry>
|
||||
<source>
|
||||
<subtitle>snarky phrase</subtitle>
|
||||
</source>
|
||||
</entry>
|
||||
</feed>
|
||||
|
14
tests/data/filter/tmpl/source_title.xml
Normal file
14
tests/data/filter/tmpl/source_title.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Description: source title
|
||||
Expect: Channels[0]['title'] == 'visible name' and Channels[0]['title_plain'] == 'visible name' and Items[0]['channel_title_plain'] == 'visible name' and Items[0]['channel_title'] == 'visible name'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<title>visible name</title>
|
||||
<entry>
|
||||
<source>
|
||||
<title>visible name</title>
|
||||
</source>
|
||||
</entry>
|
||||
</feed>
|
||||
|
14
tests/data/filter/tmpl/source_updated.xml
Normal file
14
tests/data/filter/tmpl/source_updated.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Description: source updated, rollover past midnight on feb 28 in leap year
|
||||
Expect: Channels[0]['last_updated_iso'] == '2004-02-29T02:14:55+00:00' and Channels[0]['last_updated_822'] == 'Sun, 29 Feb 2004 02:14:55 +0000' and Items[0]['channel_last_updated_iso'] == '2004-02-29T02:14:55+00:00' and Items[0]['channel_last_updated_822'] == 'Sun, 29 Feb 2004 02:14:55 +0000'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<updated>2004-02-28T18:14:55-08:00</updated>
|
||||
<entry>
|
||||
<source>
|
||||
<updated>2004-02-28T18:14:55-08:00</updated>
|
||||
</source>
|
||||
</entry>
|
||||
</feed>
|
||||
|
10
tests/data/filter/tmpl/summary_html.xml
Normal file
10
tests/data/filter/tmpl/summary_html.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<!--
|
||||
Description: entity encoded html summary
|
||||
Expect: Items[0]['content'] == 'Détente'
|
||||
-->
|
||||
|
||||
<feed xmns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<summary type="html">D&eacute;tente</summary>
|
||||
</entry>
|
||||
</feed>
|
10
tests/data/filter/tmpl/summary_lang.xml
Normal file
10
tests/data/filter/tmpl/summary_lang.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<!--
|
||||
Description: summary value
|
||||
Expect: Items[0]['content'] == 'foo' and Items[0]['summary_language'] == 'en-us'
|
||||
-->
|
||||
|
||||
<feed xmns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<summary xml:lang="en-us">foo</summary>
|
||||
</entry>
|
||||
</feed>
|
10
tests/data/filter/tmpl/summary_text.xml
Normal file
10
tests/data/filter/tmpl/summary_text.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<!--
|
||||
Description: plain text summary
|
||||
Expect: Items[0]['content'] == 'AT&T'
|
||||
-->
|
||||
|
||||
<feed xmns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<summary type="text">AT&T</summary>
|
||||
</entry>
|
||||
</feed>
|
13
tests/data/filter/tmpl/summary_xhtml.xml
Normal file
13
tests/data/filter/tmpl/summary_xhtml.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
Description: xhtml summary
|
||||
Expect: Items[0]['content'] == 'A <b>very</b> bad day'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<summary type="xhtml">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">A <b>very</b> bad day</div>
|
||||
</summary>
|
||||
</entry>
|
||||
</feed>
|
||||
|
10
tests/data/filter/tmpl/title_html.xml
Normal file
10
tests/data/filter/tmpl/title_html.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<!--
|
||||
Description: entity encoded html title
|
||||
Expect: Items[0]['title'] == 'Détente' and Items[0]['title_plain'] == 'D\xc3\xa9tente'
|
||||
-->
|
||||
|
||||
<feed xmns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<title type="html">D&eacute;tente</title>
|
||||
</entry>
|
||||
</feed>
|
10
tests/data/filter/tmpl/title_lang.xml
Normal file
10
tests/data/filter/tmpl/title_lang.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<!--
|
||||
Description: title value
|
||||
Expect: Items[0]['title'] == 'foo' and Items[0]['title_language'] == 'en-us' and Items[0]['title_plain'] == 'foo'
|
||||
-->
|
||||
|
||||
<feed xmns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<title xml:lang="en-us">foo</title>
|
||||
</entry>
|
||||
</feed>
|
10
tests/data/filter/tmpl/title_text.xml
Normal file
10
tests/data/filter/tmpl/title_text.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<!--
|
||||
Description: plain text title
|
||||
Expect: Items[0]['title'] == 'AT&T' and Items[0]['title_plain'] == 'AT&T'
|
||||
-->
|
||||
|
||||
<feed xmns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<title type="text">AT&T</title>
|
||||
</entry>
|
||||
</feed>
|
13
tests/data/filter/tmpl/title_xhtml.xml
Normal file
13
tests/data/filter/tmpl/title_xhtml.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
Description: xhtml title
|
||||
Expect: Items[0]['title'] == 'A <b>very</b> bad day' and Items[0]['title_plain'] == 'A very bad day'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<title type="xhtml">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">A <b>very</b> bad day</div>
|
||||
</title>
|
||||
</entry>
|
||||
</feed>
|
||||
|
11
tests/data/filter/tmpl/updated.xml
Normal file
11
tests/data/filter/tmpl/updated.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<!--
|
||||
Description: updated, rollover past midnight on feb 28 in leap year
|
||||
Expect: Items[0]['updated_822'] == 'Sun, 29 Feb 2004 02:14:55 +0000' and Items[0]['updated_iso'] == '2004-02-29T02:14:55+00:00' and Items[0]['updated'] == 'February 29, 2004 02:14 AM'
|
||||
-->
|
||||
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<updated>2004-02-28T18:14:55-08:00</updated>
|
||||
</entry>
|
||||
</feed>
|
||||
|
37
tests/test_filter_tmpl.py
Normal file
37
tests/test_filter_tmpl.py
Normal file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import unittest, os, sys, glob, new, re, StringIO, time
|
||||
from planet.shell import tmpl
|
||||
|
||||
testfiles = 'tests/data/filter/tmpl/%s.xml'
|
||||
|
||||
class FilterTmplTest(unittest.TestCase):
|
||||
desc_re = re.compile("Description:\s*(.*?)\s*Expect:\s*(.*)\s*-->")
|
||||
simple_re = re.compile("^(\S+) == (u?'[^']*'|\([0-9, ]+\))$")
|
||||
|
||||
def eval(self, name):
|
||||
# read the test case
|
||||
try:
|
||||
testcase = open(testfiles % name)
|
||||
data = testcase.read()
|
||||
description, expect = self.desc_re.search(data).groups()
|
||||
testcase.close()
|
||||
except:
|
||||
raise RuntimeError, "can't parse %s" % name
|
||||
|
||||
# map to template info
|
||||
results = tmpl.template_info(data)
|
||||
|
||||
# verify the results
|
||||
if not self.simple_re.match(expect):
|
||||
self.assertTrue(eval(expect, results), expect)
|
||||
else:
|
||||
lhs, rhs = self.simple_re.match(expect).groups()
|
||||
self.assertEqual(eval(rhs), eval(lhs, results))
|
||||
|
||||
# build a test method for each test file
|
||||
for testcase in glob.glob(testfiles % '*'):
|
||||
root = os.path.splitext(os.path.basename(testcase))[0]
|
||||
func = lambda self, name=root: self.eval(name)
|
||||
method = new.instancemethod(func, None, FilterTmplTest)
|
||||
setattr(FilterTmplTest, "test_" + root, method)
|
@ -4,6 +4,7 @@
|
||||
[Planet]
|
||||
template_files:
|
||||
atom.xml.xslt
|
||||
rss20.xml.tmpl
|
||||
foafroll.xml.xslt
|
||||
index.html.xslt
|
||||
opml.xml.xslt
|
||||
|
30
themes/common/rss20.xml.tmpl
Normal file
30
themes/common/rss20.xml.tmpl
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0"?>
|
||||
<rss version="2.0">
|
||||
|
||||
<channel>
|
||||
<title><TMPL_VAR name></title>
|
||||
<link><TMPL_VAR link ESCAPE="HTML"></link>
|
||||
<language>en</language>
|
||||
<description><TMPL_VAR name ESCAPE="HTML"> - <TMPL_VAR link ESCAPE="HTML"></description>
|
||||
|
||||
<TMPL_LOOP Items>
|
||||
<item>
|
||||
<title><TMPL_VAR channel_name ESCAPE="HTML"><TMPL_IF title>: <TMPL_VAR title_plain ESCAPE="HTML"></TMPL_IF></title>
|
||||
<guid><TMPL_VAR id ESCAPE="HTML"></guid>
|
||||
<link><TMPL_VAR link ESCAPE="HTML"></link>
|
||||
<TMPL_IF content>
|
||||
<description><TMPL_VAR content ESCAPE="HTML"></description>
|
||||
</TMPL_IF>
|
||||
<pubDate><TMPL_VAR date_822></pubDate>
|
||||
<TMPL_IF author_email>
|
||||
<TMPL_IF author_name>
|
||||
<author><TMPL_VAR author_email> (<TMPL_VAR author_name>)</author>
|
||||
<TMPL_ELSE>
|
||||
<author><TMPL_VAR author_email></author>
|
||||
</TMPL_IF>
|
||||
</TMPL_IF>
|
||||
</item>
|
||||
</TMPL_LOOP>
|
||||
|
||||
</channel>
|
||||
</rss>
|
Loading…
x
Reference in New Issue
Block a user