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 """
|
""" Splice together a planet from a cache of feed entries """
|
||||||
import glob, os, time, shutil
|
import glob, os, time, shutil
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
import planet, config, feedparser, reconstitute
|
import planet, config, feedparser, reconstitute, shell
|
||||||
from reconstitute import createTextElement, date
|
from reconstitute import createTextElement, date
|
||||||
from spider import filename
|
from spider import filename
|
||||||
|
|
||||||
@ -57,53 +57,9 @@ def apply(doc):
|
|||||||
if not os.path.exists(output_dir): os.makedirs(output_dir)
|
if not os.path.exists(output_dir): os.makedirs(output_dir)
|
||||||
log = planet.getLogger(config.log_level())
|
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
|
# Go-go-gadget-template
|
||||||
for template_file in config.template_files():
|
for template_file in config.template_files():
|
||||||
for template_dir in config.template_directories():
|
shell.run(template_file, doc)
|
||||||
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)
|
|
||||||
|
|
||||||
# Process bill of materials
|
# Process bill of materials
|
||||||
for copy_file in config.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]
|
[Planet]
|
||||||
template_files:
|
template_files:
|
||||||
atom.xml.xslt
|
atom.xml.xslt
|
||||||
|
rss20.xml.tmpl
|
||||||
foafroll.xml.xslt
|
foafroll.xml.xslt
|
||||||
index.html.xslt
|
index.html.xslt
|
||||||
opml.xml.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