Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

mv2

git-svn-id: https://svn.bluedynamics.eu/svn/module/bda.bfg.tile/trunk@50 f119a143-da5b-4457-81e3-bee00661a780
  • Loading branch information...
commit 01648bbf77817895e4f21047cc0b09dc3e05d02f 1 parent fb6287a
jensens authored
View
0  README.txt
No changes.
View
44 setup.py
@@ -0,0 +1,44 @@
+from setuptools import setup, find_packages
+import sys, os
+
+version = '1.0'
+shortdesc = 'Handle web application parts as tiles.'
+longdesc = open(os.path.join(os.path.dirname(__file__), 'src', 'bda', 'bfg',
+ 'tile', '_api.txt')).read()
+
+setup(name='bda.bfg.tile',
+ version=version,
+ description=shortdesc,
+ long_description=longdesc,
+ classifiers=[
+ 'Development Status :: 3 - Alpha',
+ 'Environment :: Web Environment',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
+ ],
+ keywords='',
+ author='BlueDynamics Alliance',
+ author_email='dev@bluedynamics.com',
+ url=u'https://svn.bluedynamics.net/svn/internal/bda.tile',
+ license='GNU General Public Licence',
+ packages=find_packages('src'),
+ package_dir = {'': 'src'},
+ namespace_packages=['bda', 'bda.bfg'],
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=[
+ 'setuptools',
+ 'repoze.bfg',
+ ],
+ dependency_links = [
+ "http://dist.repoze.org/bfg/1.0/",
+ ],
+ extras_require = dict(
+ test=[
+ 'interlude',
+ ]
+ ),
+ tests_require=['interlude'],
+ test_suite="bda.bfg.tile.tests.test_suite",
+ )
View
1  src/bda/__init__.py
@@ -0,0 +1 @@
+__import__('pkg_resources').declare_namespace(__name__)
View
1  src/bda/bfg/__init__.py
@@ -0,0 +1 @@
+__import__('pkg_resources').declare_namespace(__name__)
View
7 src/bda/bfg/tile/__init__.py
@@ -0,0 +1,7 @@
+from _api import render_template
+from _api import render_template_to_response
+from _api import ITile
+from _api import TileRenderer
+from _api import Tile
+from _api import registerTile
+from _api import tile
View
176 src/bda/bfg/tile/_api.py
@@ -0,0 +1,176 @@
+import os
+from zope.interface import Interface, Attribute, implements
+from zope.component import queryUtility
+from zope.component import getMultiAdapter
+from zope.component import ComponentLookupError
+from repoze.bfg.threadlocal import get_current_registry
+from webob import Response
+from webob.exc import HTTPFound
+from repoze.bfg.interfaces import IRequest
+from repoze.bfg.interfaces import IResponseFactory
+from repoze.bfg.interfaces import IAuthenticationPolicy
+from repoze.bfg.interfaces import IViewPermission
+from repoze.bfg.path import caller_package
+from repoze.bfg.renderers import template_renderer_factory
+from repoze.bfg.chameleon_zpt import ZPTTemplateRenderer
+#from repoze.bfg.security import ViewPermissionFactory
+from repoze.bfg.security import has_permission
+
+class ITile(Interface):
+ """returns on call some HTML snippet."""
+
+ def __call__(model, request):
+ """Renders the tile.
+
+ It's intended to work this way: First it calls its own prepare method,
+ then it checks its own show attribute. If this returns True it renders
+ the template in the context of the ITile implementing class instance.
+ """
+
+ def prepare():
+ """Prepares the tile.
+
+ I.e. fetch data to display ...
+ """
+
+ show = Attribute("""Render this tile?""")
+
+def _update_kw(**kw):
+ if not ('request' in kw and 'model' in kw):
+ raise ValueError, "Eexpected kwargs missing: model, request."
+ kw.update({'tile': TileRenderer(kw['model'], kw['request'])})
+ return kw
+
+def _redirect(kw):
+ if kw['request'].environ.get('redirect'):
+ return True
+ return False
+
+def render_template(path, **kw):
+ kw = _update_kw(**kw)
+ if _redirect(kw):
+ return u''
+ renderer = template_renderer_factory(path, ZPTTemplateRenderer)
+ return renderer(kw, {})
+
+def render_template_to_response(path, **kw):
+ kw = _update_kw(**kw)
+ kw['request'].environ['redirect'] = None
+ renderer = template_renderer_factory(path, ZPTTemplateRenderer)
+ result = renderer(kw, {})
+ if _redirect(kw):
+ return HTTPFound(location=kw['request'].environ['redirect'])
+ response_factory = queryUtility(IResponseFactory, default=Response)
+ return response_factory(result)
+
+class Tile(object):
+ implements(ITile)
+
+ def __init__(self, path, attribute):
+ self.path = path
+ self.attribute = attribute
+
+ def __call__(self, model, request):
+ self.model = model
+ self.request = request
+ self.prepare() # XXX maybe remove.
+ if not self.show:
+ return u''
+ if self.path:
+ try:
+ # XXX: do not catch exception.
+ return render_template(self.path, request=request,
+ model=model, context=self)
+ except Exception, e:
+ return u"Error:<br /><pre>%s</pre>" % e
+ renderer = getattr(self, self.attribute)
+ result = renderer()
+ return result
+
+ @property
+ def show(self):
+ return True
+
+ def prepare(self):
+ pass
+
+ def render(self):
+ return u''
+
+ def redirect(self, url):
+ self.request.environ['redirect'] = url
+
+ @property
+ def nodeurl(self):
+ relpath = [p for p in self.model.path if p is not None]
+ return '/'.join([self.request.application_url] + relpath)
+
+class TileRenderer(object):
+
+ def __init__(self, model, request):
+ self.model, self.request = model, request
+
+ def __call__(self, name):
+ registry = get_current_registry()
+ # XXX fix me. new API in repoze.bfg
+ #secured = not not registry.queryUtility(IAuthenticationPolicy)
+ #if secured:
+ # permitted = registry.getMultiAdapter((self.model, self.request),
+ # IViewPermission,
+ # name=name)
+ # if not permitted:
+ # return u'permission denied'
+ try:
+ tile = getMultiAdapter((self.model, self.request), ITile, name=name)
+ except ComponentLookupError, e:
+ return u"Tile with name '%s' not found:<br /><pre>%s</pre>" % \
+ (name, e)
+ return tile
+
+# Registration
+def registerTile(name, path=None, attribute='render',
+ interface=Interface, _class=Tile, permission='view'):
+ if isinstance(interface, basestring):
+ pass # XXX: lookup
+ if path:
+ if not (':' in path or os.path.isabs(path)):
+ caller = caller_package(level=1)
+ path = '%s:%s' % (caller.__name__, path)
+ factory = _class(path, attribute)
+ registry = get_current_registry()
+ registry.registerAdapter(factory, [interface, IRequest],
+ ITile, name, event=False)
+ # XXX fix me. new API in repoze.bfg
+ #if permission:
+ # factory = ViewPermissionFactory(permission)
+ # registry.registerAdapter(factory, [interface, IRequest],
+ # IViewPermission, name)
+
+class tile(object):
+ """Tile decorator.
+ """
+
+ def __init__(self, name, path=None, attribute='render',
+ interface=Interface, permission='view', level=2):
+ """name to register as, path to template, interface adapting to.
+ level is a special to make doctests pass the magic path-detection.
+ you should never need latter.
+ """
+ self.name = name
+ self.path = path
+ if path:
+ if not (':' in path or os.path.isabs(path)):
+ caller = caller_package(level)
+ self.path = '%s:%s' % (caller.__name__, path)
+ self.attribute = attribute
+ self.interface = interface
+ self.permission = permission
+
+ def __call__(self, ob):
+ registerTile(self.name,
+ self.path,
+ self.attribute,
+ interface=self.interface,
+ _class=ob,
+ permission=self.permission)
+ return ob
View
63 src/bda/bfg/tile/_api.txt
@@ -0,0 +1,63 @@
+A tile is a piece of web application, i.e. a form, a navigation, etc.
+
+Splitting your application in such small and logic application parts makes it
+easy to re-use this application, simplifies application ajaxification and
+the use of same application parts in different manners.
+
+Imports.:
+
+ >>> from bda.bfg.tile import Tile
+ >>> from bda.bfg.tile import TileRenderer
+ >>> from bda.bfg.tile import registerTile
+ >>> from bda.bfg.tile import tile
+
+We need some dummies as model and request.:
+
+ >>> class Model(object): pass
+ >>> model = Model()
+ >>> from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
+ >>> request = DEFAULT_REQUEST_FACTORIES[None]['factory'](environ={})
+
+The pure Tile itself. Normally you do not create this directly, this is done
+due registration, see below.:
+
+ >>> mytile = Tile('testdata/tile1.pt', None)
+ >>> mytile(model, request)
+ u'<span>Tile One</span>'
+
+Register a tile using the prior template testtemplate. When no object is given,
+the default tile is instanciated as above.:
+
+ >>> registerTile('tileone', 'testdata/tile1.pt')
+
+Render the already registered tile.:
+
+ >>> TileRenderer(model, request)('tileone')
+ u'<span>Tile One</span>'
+
+Now the decorator - level=1 is needed for the doctest only to reduce the module
+level.:
+
+ >>> @tile('tiletwo', 'testdata/tile2.pt', level=1)
+ ... class Tile2(Tile):
+ ... data = u'custom'
+ >>> TileRenderer(model, request)('tiletwo')
+ u'<span>Tile Two: <b><span>Tile One</span></b></span>'
+
+You can define an attribute which is responsible to render the tile instead of
+defining a template. By default ``render`` is taken. With the keyword argument
+``attribute`` you can point to a different attribute.:
+
+ >>> @tile('attrtile')
+ ... class Tile2(Tile):
+ ... def render(self):
+ ... return u'<h1>Rendered via attribute call</h1>'
+ >>> TileRenderer(model, request)('attrtile')
+ u'<h1>Rendered via attribute call</h1>'
+
+ >>> @tile('attrtile', attribute='foobar')
+ ... class Tile2(Tile):
+ ... def foobar(self):
+ ... return u'<h1>Rendered via attribute foobar call</h1>'
+ >>> TileRenderer(model, request)('attrtile')
+ u'<h1>Rendered via attribute foobar call</h1>'
View
1  src/bda/bfg/tile/testdata/main1.pt
@@ -0,0 +1 @@
+<html><body><div tal:content="structure tile('tileone')" /></body></html>
View
1  src/bda/bfg/tile/testdata/main2.pt
@@ -0,0 +1 @@
+<html><body><div tal:content="structure tile('tiletwo')" /></body></html>
View
1  src/bda/bfg/tile/testdata/main3.pt
@@ -0,0 +1 @@
+<html><body><div tal:content="structure tile('tilethree')" /></body></html>
View
1  src/bda/bfg/tile/testdata/tile1.pt
@@ -0,0 +1 @@
+<span>Tile One</span>
View
1  src/bda/bfg/tile/testdata/tile2.pt
@@ -0,0 +1 @@
+<span>Tile Two: <b tal:content="structure tile('tileone')"/></span>
View
1  src/bda/bfg/tile/testdata/tile2_1.pt
@@ -0,0 +1 @@
+<span>second level</span>
View
1  src/bda/bfg/tile/testdata/tile3.pt
@@ -0,0 +1 @@
+<span>Tile Three: <tal: tal:replace="context.data" /></span>
View
25 src/bda/bfg/tile/tests.py
@@ -0,0 +1,25 @@
+import unittest
+import doctest
+from pprint import pprint
+from interlude import interact
+
+optionflags = doctest.NORMALIZE_WHITESPACE | \
+ doctest.ELLIPSIS #| \
+ #doctest.REPORT_ONLY_FIRST_FAILURE
+
+TESTFILES = [
+ '_api.txt',
+]
+
+def test_suite():
+ return unittest.TestSuite([
+ doctest.DocFileSuite(
+ file,
+ optionflags=optionflags,
+ globs={'interact': interact,
+ 'pprint': pprint},
+ ) for file in TESTFILES
+ ])
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Please sign in to comment.
Something went wrong with that request. Please try again.