changeset 70:262fb90a54b4

make template loading lenient and other fixes; bump version
author Jeff Hammel <jhammel@mozilla.com>
date Sat, 04 Aug 2012 15:55:52 -0700
parents 9fac58348520
children 94298e137131
files decoupage/formats.py decoupage/formatters.py decoupage/templates/index.html decoupage/web.py setup.py
diffstat 5 files changed, 32 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/decoupage/formats.py
+++ b/decoupage/formats.py
@@ -22,28 +22,28 @@ class JSON(object):
   def __call__(self, request, data):
 
     # fix datetime
     for f in data['files']:
       if 'modified' in f:
         f['modified'] = f['modified'].ctime()
 
     return 'application/json', json.dumps(data['files'])
-  
+
 class RSS(object):
   """RSS for indices"""
 
   def __init__(self, app, count=10, cascade=False):
     self.app = app # the decoupage
     self.count = int(count)
     self.cascade = cascade
 
   def __call__(self, request, data):
     items = [ PyRSS2Gen.RSSItem(title=item['name'],
-                                description=item['description'] or item['name'],
+                                description=item['description'] or item.get('title') or item['name'],
                                 pubDate=item['modified'],
                                 guid=PyRSS2Gen.Guid(link(request, item['path'])))
               for item in data['files'] ]
     path_link = link(request, data['path'])
     rss = PyRSS2Gen.RSS2(title=data['title'] or data['path'],
                          link=path_link,
                          description=data['title'] or data['path'],
                          lastBuildDate = datetime.datetime.now(),
--- a/decoupage/formatters.py
+++ b/decoupage/formatters.py
@@ -12,16 +12,17 @@ class FormatterBase(object):
     abstract base class if you want to use __init__ methods
     in the form of
     'arg1, arg2, arg3, kw1=foo, kw2=bar, kw3=baz
     """
 
     defaults = {} # default values for attrs to be set on the instance
 
     def __init__(self, string):
+        self._string = string
         args = [ i.strip() for i in string.split(',')]
         for index, arg in enumerate(args):
             if '=' in arg:
                 break
         else:
             self.args = args
             for key, default in self.defaults.items():
                 setattr(self, key, default)
@@ -169,16 +170,28 @@ class TitleDescription(FormatterBase):
     Arguments:
     * separator: what separator to use (':' by default)
     """
     # XXX what about setting the page title?
 
     defaults = { 'separator': ':' }
 
     def __call__(self, request, data):
+
+        # title webpage
+        title = self._string
+        if ':' in title:
+            _title, url = [i.strip() for i in title.split(':', 1)]
+            if '://' in url:
+                # XXX could also use urlparse
+                title = _title
+                data['link'] = url
+        data['title'] = title
+
+        # title files
         for f in data['files']:
             if f['description'] and self.separator in f['description']:
                 title, description = f['description'].split(self.separator, 1)
                 title = title.strip()
                 description = description.strip()
                 if not title:
                     title = f['name']
                 f['title'] = title
--- a/decoupage/templates/index.html
+++ b/decoupage/templates/index.html
@@ -5,17 +5,17 @@
       xmlns:py="http://genshi.edgewall.org/"
       xmlns:xi="http://www.w3.org/2001/XInclude">
   <!-- basic index of files -->
   <head>
     <xi:include href="head.html"/>
   </head>
   <body>
     <xi:include py:if="include" href="${include}"/>
-    <h1 py:if="title">${title}</h1>
+    <h1 py:if="title"><a py:if="link" href="${link}">${title}</a><py:if test="not link">${title}</py:if></h1>
     <ul id="listing">
       <li py:for="f in files">
         <a name="${f['path']}"></a>
         <a href="${f['path']}">
           ${f.get('title', f['description']) or f['name']}</a><span py:if="'title' in f and f['description']">: ${f['description']}
           </span>
           <py:if test="'links' in f">
             <span py:for="link in f['links']" class="link">
--- a/decoupage/web.py
+++ b/decoupage/web.py
@@ -68,50 +68,51 @@ class Decoupage(object):
                 _cls = _format.load()
                 _instance = _cls(self, **format_args.get(_format.name, {}))
             except Exception, e:
                 # record the error, but persist
                 print >> sys.stderr, "Couldn't load format: %s" % _format
                 print >> sys.stderr, e
                 continue
             self.formats[_format.name] = _instance
-        
+
         # pluggable index data formatters
         self.formatters = {}
         for formatter in iter_entry_points('decoupage.formatters'):
             try:
                 _formatter = formatter.load()
                 template_dir = resource_filename(formatter.module_name, 'templates')
                 if template_dir not in self.template_directories and os.path.isdir(template_dir):
                     self.template_directories.append(template_dir)
             except Exception, e:
                 # record the error, but persist
                 print >> sys.stderr, "Couldn't load formatter: %s" % formatter
                 print >> sts.stderr, e
-                continue 
+                continue
             self.formatters[formatter.name] = _formatter
-        
+
         # template loader
-        self.loader = TemplateLoader(self.template_directories, 
+        self.loader = TemplateLoader(self.template_directories,
+                                     variable_lookup="lenient",
                                      auto_reload=self.auto_reload)
 
-        
+
 
     ### methods dealing with HTTP
-        
+
     def __call__(self, environ, start_response):
 
         # boilerplate: request and filename
         request = Request(environ)
         filename = request.path_info.strip('/')
         path = os.path.join(self.directory, filename)
 
         # check to see what we have to serve
         if os.path.exists(path):
-            
+
             if os.path.isdir(path):
                 # serve an index
                 if request.path_info.endswith('/'):
                     res = self.get(request)
                 else:
                     res = exc.HTTPMovedPermanently(add_slash=True)
                 return res(environ, start_response)
 
@@ -124,55 +125,50 @@ class Decoupage(object):
                     for i in conf:
                         if i.startswith('/'):
                             name = i[1:]
                             if name in transformers:
                                 kwargs[name] = dict([j.split('=', 1) for j in conf[i].split(',') if '=' in j])
                     fileserver = FileTypeTransformer(*args, **kwargs)
                 else:
                     fileserver = self.fileserver
-                    
+
                 fileserver = fileserver(path)
                 return fileserver(environ, start_response)
         else:
             # file does not exist
             response = exc.HTTPNotFound()
             return response(environ, start_response)
 
 
     def get(self, request):
         """
         return response to a GET requst
         """
-        
-        # ensure a sane path        
+
+        # ensure a sane path
         path = request.path_info.strip('/')
         directory = os.path.join(self.directory, path)
         path = '/%s' % path
-        
+
         # get the configuraton
         conf = self.conf(path)
 
         ### build data dictionary
         # TODO: separate these out into several formatters
         files = self.filedata(path, directory, conf)
         data = {'path': path, 'files': files, 'request': request }
 
         # add a function to get the path to files
         data['filepath'] = lambda *segments: os.path.join(*([directory] + list(segments)))
 
-        # defaults; TODO: make this better
-        # there shouldn't need to be defaults;
-        # iirc, genshi has a mode where these will default to None
-        data['title'] = conf.get('/title')
+        # defaults
         data['directory'] = directory
-        data['include'] = None
         data['css'] = ()
         data['scripts'] = ()
-        data['icon'] = None
 
         # apply formatters
         # XXX this should be cached if not self.auto_reload
         if '/formatters' in conf:
             # ordered list of formatters to be applied first
             formatters = [ i for i in conf['/formatters'].split()
                            if i in self.formatters ]
         else:
--- a/setup.py
+++ b/setup.py
@@ -1,33 +1,33 @@
 from setuptools import setup, find_packages
 
 # use README as long_description
 try:
     description = file("README.txt").read()
 except IOError:
     description = ''
 
-version = '0.10.3'
+version = '0.11'
 
 setup(name='decoupage',
       version=version,
       description="Decoupage is the art of decorating an object by gluing colored paper cutouts onto it in combination with special paint effects ... The software decoupage lets you stitch together index pages from filesystem content",
       long_description=description,
       classifiers=[], # Get strings from http://www.python.org/pypi?%3Aaction=list_classifiers
       author='Jeff Hammel',
       author_email='k0scist@gmail.com',
       url='http://k0s.org',
       license="GPL",
       packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
       include_package_data=True,
       zip_safe=False,
       install_requires=[
           # -*- Extra requirements: -*-
-          'WebOb',	
+          'WebOb',
           'Paste',
           'PasteScript',
           'genshi',
           'martINI>=0.4',
           'contenttransformer>=0.3.3',
           'PyRSS2Gen',
          ],
       dependency_links=['http://www.dalkescientific.com/Python/PyRSS2Gen-1.0.0.tar.gz#egg=PyRSS2Gen'],
@@ -54,9 +54,9 @@ setup(name='decoupage',
       links = decoupage.formatters:Links
       order = decoupage.formatters:Order
       scripts = decoupage.formatters:JavaScript
       sort = decoupage.formatters:Sort
       title = decoupage.formatters:TitleDescription
       up = decoupage.formatters:Up
       """,
       )
-      
+