Permalink
Browse files

Modify store to support using internally-stored templates rather than

requiring a templates/ directory in the media tree always.

Modify scripts/run.py to use this new ability to easily run a command
line Singleshot on an image tree.

Replace PyRSS2Gen with new ElementTree-based RSS2 generator (reduce
dependencies).  Still need to flesh out the feed to have more details.

Add main to jpeg.py for quick testing of JpegHeader.

Fix misclosed tags in built-in templates.
  • Loading branch information...
Ken
Ken committed Jun 4, 2009
1 parent 8e23b50 commit 22729753947a12b245e3f00e950f190bd450bc5d
View
@@ -0,0 +1,3 @@
*.pyc
singleshot.egg-info
tests/view/
View
@@ -4,11 +4,8 @@
import singleshot.serve
import singleshot.ssconfig
import os
import sys
jroot = '../../sites/photos.xythian.com'
root = '../singleshot_testroot'
root = os.path.abspath(root)
templates = os.path.join(root, 'templates')
store = singleshot.ssconfig.create_store(root, template_root=templates)
root = os.path.abspath(sys.argv[1])
store = singleshot.ssconfig.create_store(root, template_root=':internal:')
singleshot.serve.serve_http(store, addr='', port=8080)
View
@@ -1,54 +1,147 @@
import PyRSS2Gen as RSS2
from datetime import datetime
from StringIO import StringIO
from xml.sax import saxutils
from xml.etree.ElementTree import ElementTree, Element, SubElement, tostring
class Convenience(object):
def __init__(self, name, uri):
if uri:
self.name = u"{%s}%s" % (uri, name)
else:
self.name = name
def create(self, **kw):
return Element(self.name, **kw)
def add(self, parent, _text=None, **attrs):
elt = SubElement(parent, self.name, **attrs)
if _text:
elt.text = _text
return elt
__call__ = add
class NSMetaHack(type):
def __new__(cls, name, bases, dct):
ns = dct['URI']
elts = dct['elts']
del dct['elts']
for elt in elts:
dct[str(elt)] = Convenience(elt, ns)
return type.__new__(cls, name, bases, dct)
class NSHack(object):
__metaclass__ = NSMetaHack
URI = u''
elts = ()
class RSS2(NSHack):
URI = None
elts = ('rss',
'channel',
'title',
'link',
'description',
'language',
'pubDate',
'lastBuildDate',
'category',
'docs',
'generator',
'managingEditor',
'webMaster',
'item',
'comments',
'guid')
class DCElement(NSHack):
URI = u'http://purl.org/dc/elements/1.1/'
elts = ('subject','creator')
class Content(NSHack):
URI = u'http://purl.org/rss/1.0/modules/content/'
elts = ('encoded',)
class RSS2Feed(object):
# ew, there's no default namespace
nsmap = {'content' : Content.URI,
'dc' : DCElement.URI}
def __init__(self, request):
self.request = request
def creator(self, item, author):
if not author:
author = self.author
DCElement.creator(item, author.name)
def date(self, elt, dt):
elt.text = dt.strftime("%a, %d %b %H:%M:%S %Y +0000")
return elt
def entry(self, channel, image):
s = StringIO()
image.view(s, viewname='rssitem',
contextdata={'absoluteitemhref' : self.request.full_url(image.href)})
try:
desc = unicode(s.getvalue())
except:
desc = ''
item = RSS2.item.add(channel)
RSS2.title.add(item, image.title)
RSS2.link.add(item, self.request.full_url(image.href))
self.date(RSS2.pubDate.add(item), image.publish_time)
RSS2.guid.add(item, self.request.full_url(image.href), isPermaLink='true')
if desc:
Content.encoded.add(item, desc)
# we don't have comment RSS feeds
return item
def feed(self, photos):
root = RSS2.rss.create(version='2.0') #, nsmap=self.nsmap)
channel = RSS2.channel.add(root)
config = self.request.store.config.config
RSS2.title.add(channel, config.get('feed', 'title'))
RSS2.link.add(channel, self.request.full_url('/'))
RSS2.description.add(channel, config.get('feed', 'description'))
# self.date(RSS2.pubDate(channel), data.updated)
# self.date(RSS2.lastBuildDate(channel), data.updated)
# if data.agent and data.agent_version:
# RSS2.generator.add(channel, "%s %s" % (data.agent, data.agent_version))
# RSS2.language.add(channel, data.lang)
for photo in photos:
self.entry(channel, photo)
return root
import codecs
import os
import sys
def handle(request):
feedzor = RSS2Feed(request)
load_view = request.store.load_view
config = request.store.config.config
rsstitle = config.get('feed', 'title')
rssdesc = config.get('feed', 'description')
rsscount = int(config.get('feed', 'recentcount'))
store = request.store
items = [load_view(path) for path in store.loader.recent_items(rsscount)]
def toitem(image):
s = StringIO()
image.view(s, viewname='rssitem',
contextdata={'absoluteitemhref' : request.full_url(image.href)})
try:
desc = unicode(s.getvalue())
except:
desc = ''
lnk = request.full_url(image.href)
return RSS2.RSSItem(title = image.title,
link = lnk,
description = unicode(desc),
guid = RSS2.Guid(lnk),
pubDate = image.publish_time)
rss = RSS2.RSS2(
title = rsstitle,
link = request.full_url('/'),
description = rssdesc,
lastBuildDate = datetime.now(),
items = [toitem(image) for image in items]
)
f = StringIO()
out = codecs.getwriter('iso-8859-1')(f)
handler = saxutils.XMLGenerator(f)
handler.startDocument()
handler.processingInstruction('xml-stylesheet', 'type="text/xsl" href="%s"' % (request.full_url('/static/rssformat.xsl')))
rss.publish(handler)
handler.endDocument()
s = f.getvalue()
photos = [load_view(path) for path in store.loader.recent_items(rsscount)]
result = tostring(feedzor.feed(photos), encoding='utf-8')
# f = StringIO()
# out = codecs.getwriter('utf-8')(f)
# handler.processingInstruction('xml-stylesheet', 'type="text/xsl" href="%s"' % (request.full_url('/static/rssformat.xsl')))
# rss.publish(handler)
# handler.endDocument()
# s = f.getvalue()
request.content_type = 'text/xml'
request.write(s)
request.write(result)
if __name__ == '__main__':
pass
View
@@ -68,8 +68,6 @@ def month_dir(fspath):
return year, month, datetime(year, month, 01, 00, 00, 00, tzinfo=Local)
else:
return None
class DirectoryFSLoader(FSLoader):
def __init__(self, store, is_item):
View
@@ -412,6 +412,13 @@ def load(self, path):
if hasattr(xmp, 'Headline'):
self.iptc.headline = str(xmp.Headline)
def main():
path = sys.argv[1]
myheader = JpegHeader(path)
print myheader.comment, (myheader.height, myheader.width), myheader.iptc.datetime, myheader.iptc.keywords
if __name__ == '__main__':
import sys
main()
View
@@ -108,6 +108,8 @@ def create_handler(path, name):
return pages.template_handler(target_path + '.html')
def page_handlers(path):
if not os.path.exists(path):
return
for item in os.listdir(path):
name, ext = os.path.splitext(item)
target_path = os.path.join(path, item)
View
@@ -56,7 +56,9 @@ def __init__(self, root, template_root=None):
self.root = root # is the root
if template_root:
if template_root == ':internal:':
self.template_root = None
elif template_root:
self.template_root = template_root
else:
self.template_root = os.path.join(self.root, 'templates')
@@ -66,7 +68,10 @@ def __init__(self, root, template_root=None):
self.static_root = os.path.join(root, 'static')
def find_template(self, filename):
return os.path.join(self.template_root, filename)
if self.template_root:
return os.path.join(self.template_root, filename)
else:
return filename
class SingleshotConfig(ConfiguredEntity):
defaults = { 'paths' : { 'invokePath' : '/bin:/usr/bin' },
@@ -119,7 +124,7 @@ def ignore_path(self, path):
return True
elif path.startswith(self.store.view_root):
return True
elif path.startswith(self.store.template_root):
elif self.store.template_root and path.startswith(self.store.template_root):
return True
elif path.startswith(self.store.page_root):
return True
View
@@ -1,17 +1,20 @@
from __future__ import nested_scopes
import imp
import sys
from simpletal import simpleTAL, simpleTALES
from simpletal.simpleTALES import PathFunctionVariable, CachedFuncResult
from simpletal.simpleTALUtils import TemplateCache, FastStringOutput
import singleshot.templates as internal_templates
from singleshot.properties import *
from itertools import chain
class CachedLoader(object):
def __init__(self):
self.cache = TemplateCache()
def load(self, path):
return self.cache.getTemplate(path)
TEMPLATE_CACHE = TemplateCache()
PATH_LOADER = CachedLoader()
class ViewableObject(object):
viewname = 'view'
@@ -21,7 +24,9 @@ class ViewableObject(object):
def load_template(self, path):
if not path:
return None
return TEMPLATE_CACHE.getTemplate(path)
if not path.startswith('/'):
return internal_templates.LOADER.load(path)
return PATH_LOADER.load(path)
def find_template(self, name):
return self.store.find_template(name + '.html')
@@ -9,11 +9,12 @@
# python packages distributed with Python 2.3's distutils.
#
from simpletal import simpleTAL
def all_templates():
return __templates.items()
mydir, myname = os.path.split(__file__)
return _templates.items()
__templates = {'404.html' : """<html><head><title>Not Found</title></head><body><h1>Not found</h1></body></html>""",
_templates = {'404.html' : """<html><head><title>Not Found</title></head><body><h1>Not found</h1></body></html>""",
'macros.html' : """<macros>
<div metal:define-macro="paginator" tal:define="p paginator"
@@ -60,9 +61,9 @@ def all_templates():
<div id="page">
<div id="header">Singleshot: <ul class="navlinks">
<li><a tal:attributes="href ssroot/">Home</a></li>
<li tal:condition="data/keyword"/><a tal:attributes="href ssroot/recent/">recent</a></li>
<li tal:condition="data/keyword"/><a tal:attributes="href ssroot/keyword/">keywords</a></li>
<li tal:condition="data/bydate"/><a tal:attributes="href ssroot/bydate/">by date</a></li>
<li tal:condition="data/keyword"><a tal:attributes="href ssroot/recent/">recent</a></li>
<li tal:condition="data/keyword"><a tal:attributes="href ssroot/keyword/">keywords</a></li>
<li tal:condition="data/bydate"><a tal:attributes="href ssroot/bydate/">by date</a></li>
</ul>
</div>
@@ -219,4 +220,13 @@ def all_templates():
}
class TemplateLoader(object):
def __init__(self):
self.compiled = {}
for k, v in _templates.items():
self.compiled[k] = simpleTAL.compileHTMLTemplate(v)
def load(self, name):
return self.compiled[name]
LOADER = TemplateLoader()

0 comments on commit 2272975

Please sign in to comment.