Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
git-svn-id: https://svn.bluedynamics.eu/svn/module/bda.bfg.tile/trunk@50 f119a143-da5b-4457-81e3-bee00661a780
- Loading branch information
jensens
committed
Nov 12, 2009
1 parent
fb6287a
commit 01648bb
Showing
15 changed files
with
324 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -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", | |||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1 @@ | |||
__import__('pkg_resources').declare_namespace(__name__) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1 @@ | |||
__import__('pkg_resources').declare_namespace(__name__) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -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>' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1 @@ | |||
<html><body><div tal:content="structure tile('tileone')" /></body></html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1 @@ | |||
<html><body><div tal:content="structure tile('tiletwo')" /></body></html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1 @@ | |||
<html><body><div tal:content="structure tile('tilethree')" /></body></html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1 @@ | |||
<span>Tile One</span> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1 @@ | |||
<span>Tile Two: <b tal:content="structure tile('tileone')"/></span> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1 @@ | |||
<span>second level</span> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1 @@ | |||
<span>Tile Three: <tal: tal:replace="context.data" /></span> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -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') |