python-toscawidgets-0.9.7.2/ 0000755 0001750 0001750 00000000000 11230574134 014350 5 ustar zack zack python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/ 0000755 0001750 0001750 00000000000 11224437421 017561 5 ustar zack zack python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/README.txt 0000644 0001750 0001750 00000003067 11175375026 021274 0 ustar zack zack ToscaWidgets
============
TW is a web widget toolkit for Python to aid in the creation, packaging and
distribution of common view elements normally used in the web.
These widgets are portable among any Python web-application framework or
application that supports the WSGI standard.
Several widget libraries exist which build on top of Toscawidgets to provide
form controls, sortable grids, maps, charts, etc.
Credits
-------
ToscaWidgets was originally developed by `Alberto Valverde Gonzalez`_ based on
the work of the many people involved in developing, testing and designing
TurboGears' Widgets. TG Widget's original design was made by TurboGears'
author, `Kevin Dangoor`_ . **Michele Cella** and Alberto worked hard to push
TG's implementation to where it now stands.
Several people have contributed to ToscaWidgets itself and external widget
packages.
Community
---------
ToscaWidgets' community interacts in the `toscawidgets-discuss`_ Google Group.
It's not rare to see discussion in Turbogears and Pylons lists too.
ToscaWidgets documentation, repository and Trac lives at
http://toscawidgets.org/
Running the tests
-----------------
The test suite can be executed by running the `test` `setuptools` command::
$ python setup.py test
.. warning::
The tests cannot be executed with `nosetests` ATM. This issue is not trivial
to fix but will be fixed before 1.0
.. _Alberto Valverde Gonzalez: mailto:alberto@toscat._nospam_.net
.. _Kevin Dangoor: http://www.blueskyonmars.com/
.. _toscawidgets-discuss: http://groups.google.com/group/toscawidgets-discuss
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/ToscaWidgets.egg-info/ 0000755 0001750 0001750 00000000000 11224437421 023653 5 ustar zack zack python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/ToscaWidgets.egg-info/requires.txt 0000644 0001750 0001750 00000000270 11224437420 026251 0 ustar zack zack WebOb
simplejson >= 2.0
[mako]
Mako >= 0.1.1
[cheetah]
Cheetah>=1.0
TurboCheetah>=0.9.5
[build_docs]
Sphinx
WidgetBrowser
[genshi]
Genshi >= 0.3.5
[kid]
kid>=0.9.5
TurboKid>=0.9.9 python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/ToscaWidgets.egg-info/namespace_packages.txt 0000644 0001750 0001750 00000000013 11224437420 030177 0 ustar zack zack tw
tw.mods
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/ToscaWidgets.egg-info/dependency_links.txt 0000644 0001750 0001750 00000000001 11224437420 027720 0 ustar zack zack
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/ToscaWidgets.egg-info/PKG-INFO 0000644 0001750 0001750 00000005363 11224437420 024756 0 ustar zack zack Metadata-Version: 1.0
Name: ToscaWidgets
Version: 0.9.7.2
Summary: Web widget creation toolkit based on TurboGears widgets
Home-page: http://toscawidgets.org/
Author: Alberto Valverde Gonzalez
Author-email: alberto@toscat.net
License: MIT
Download-URL: http://toscawidgets.org/download/
Description: TW is a web widget toolkit for Python to aid in the creation, packaging and
distribution of common view elements normally used in the web.
These widgets are portable among any Python web-application framework or
application that supports the WSGI standard.
Several widget libraries exist which build on top of Toscawidgets to provide
form controls, sortable grids, maps, charts, etc.
Credits
-------
ToscaWidgets was originally developed by `Alberto Valverde Gonzalez`_ based on
the work of the many people involved in developing, testing and designing
TurboGears' Widgets. TG Widget's original design was made by TurboGears'
author, `Kevin Dangoor`_ . **Michele Cella** and Alberto worked hard to push
TG's implementation to where it now stands.
Several people have contributed to ToscaWidgets itself and external widget
packages.
Community
---------
ToscaWidgets' community interacts in the `toscawidgets-discuss`_ Google Group.
It's not rare to see discussion in Turbogears and Pylons lists too.
ToscaWidgets documentation, repository and Trac lives at
http://toscawidgets.org/
Running the tests
-----------------
The test suite can be executed by running the `test` `setuptools` command::
$ python setup.py test
.. warning::
The tests cannot be executed with `nosetests` ATM. This issue is not trivial
to fix but will be fixed before 1.0
.. _Alberto Valverde Gonzalez: mailto:alberto@toscat._nospam_.net
.. _Kevin Dangoor: http://www.blueskyonmars.com/
.. _toscawidgets-discuss: http://groups.google.com/group/toscawidgets-discuss
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Environment :: Web Environment :: ToscaWidgets
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware
Classifier: Topic :: Software Development :: Widget Sets
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/ToscaWidgets.egg-info/entry_points.txt 0000644 0001750 0001750 00000001217 11224437420 027151 0 ustar zack zack
[distutils.commands]
archive_tw_resources = tw.core.command:archive_tw_resources
[python.templating.engines]
toscawidgets = tw.core.engine_plugin:ToscaWidgetsTemplatePlugin
[toscawidgets.host_frameworks]
wsgi = tw.mods.wsgi:WSGIHostFramework
pylons = tw.mods.pylonshf:PylonsHostFramework
turbogears = tw.mods.tg:Turbogears
[toscawidgets.widgets]
widgets = tw.api
resources = tw.api
[paste.paster_create_template]
toscawidgets=tw.paste_template:ToscaWidgetsTemplate
[turbogears.extensions]
toscawidgets=tw.mods.tg
[paste.filter_app_factory]
middleware = tw.api:make_middleware
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/ToscaWidgets.egg-info/top_level.txt 0000644 0001750 0001750 00000000003 11224437420 026375 0 ustar zack zack tw
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/ToscaWidgets.egg-info/not-zip-safe 0000644 0001750 0001750 00000000001 11175375042 026106 0 ustar zack zack
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/ToscaWidgets.egg-info/SOURCES.txt 0000644 0001750 0001750 00000003142 11224437421 025537 0 ustar zack zack MANIFEST.in
README.txt
setup.cfg
setup.py
ToscaWidgets.egg-info/PKG-INFO
ToscaWidgets.egg-info/SOURCES.txt
ToscaWidgets.egg-info/dependency_links.txt
ToscaWidgets.egg-info/entry_points.txt
ToscaWidgets.egg-info/namespace_packages.txt
ToscaWidgets.egg-info/not-zip-safe
ToscaWidgets.egg-info/requires.txt
ToscaWidgets.egg-info/top_level.txt
tw/__init__.py
tw/api.py
tw/paste_template.py
tw/release.py
tw/core/__init__.py
tw/core/base.py
tw/core/command.py
tw/core/engine_plugin.py
tw/core/exceptions.py
tw/core/js.py
tw/core/mako_util.py
tw/core/meta.py
tw/core/middleware.py
tw/core/registry.py
tw/core/resource_injector.py
tw/core/resources.py
tw/core/testutil.py
tw/core/util.py
tw/core/view.py
tw/mods/__init__.py
tw/mods/base.py
tw/mods/cp2.py
tw/mods/cp3.py
tw/mods/pylonshf.py
tw/mods/tg.py
tw/mods/wsgi.py
tw/paste_templates/__init__.py
tw/paste_templates/__init__.pyc
tw/paste_templates/widget_template/MANIFEST.in_tmpl
tw/paste_templates/widget_template/setup.cfg_tmpl
tw/paste_templates/widget_template/setup.py_tmpl
tw/paste_templates/widget_template/+egg+.egg-info/paster_plugins.txt
tw/paste_templates/widget_template/docs/conf.py_tmpl
tw/paste_templates/widget_template/docs/index.rst_tmpl
tw/paste_templates/widget_template/tests/__init__.py_tmpl
tw/paste_templates/widget_template/tests/test_widget.py_tmpl
tw/paste_templates/widget_template/tw/__init__.py_tmpl
tw/paste_templates/widget_template/tw/+package+/__init__.py_tmpl
tw/paste_templates/widget_template/tw/+package+/release.py_tmpl
tw/paste_templates/widget_template/tw/+package+/samples.py_tmpl
tw/paste_templates/widget_template/tw/+package+/widgets.py_tmpl python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/PKG-INFO 0000644 0001750 0001750 00000005363 11224437421 020665 0 ustar zack zack Metadata-Version: 1.0
Name: ToscaWidgets
Version: 0.9.7.2
Summary: Web widget creation toolkit based on TurboGears widgets
Home-page: http://toscawidgets.org/
Author: Alberto Valverde Gonzalez
Author-email: alberto@toscat.net
License: MIT
Download-URL: http://toscawidgets.org/download/
Description: TW is a web widget toolkit for Python to aid in the creation, packaging and
distribution of common view elements normally used in the web.
These widgets are portable among any Python web-application framework or
application that supports the WSGI standard.
Several widget libraries exist which build on top of Toscawidgets to provide
form controls, sortable grids, maps, charts, etc.
Credits
-------
ToscaWidgets was originally developed by `Alberto Valverde Gonzalez`_ based on
the work of the many people involved in developing, testing and designing
TurboGears' Widgets. TG Widget's original design was made by TurboGears'
author, `Kevin Dangoor`_ . **Michele Cella** and Alberto worked hard to push
TG's implementation to where it now stands.
Several people have contributed to ToscaWidgets itself and external widget
packages.
Community
---------
ToscaWidgets' community interacts in the `toscawidgets-discuss`_ Google Group.
It's not rare to see discussion in Turbogears and Pylons lists too.
ToscaWidgets documentation, repository and Trac lives at
http://toscawidgets.org/
Running the tests
-----------------
The test suite can be executed by running the `test` `setuptools` command::
$ python setup.py test
.. warning::
The tests cannot be executed with `nosetests` ATM. This issue is not trivial
to fix but will be fixed before 1.0
.. _Alberto Valverde Gonzalez: mailto:alberto@toscat._nospam_.net
.. _Kevin Dangoor: http://www.blueskyonmars.com/
.. _toscawidgets-discuss: http://groups.google.com/group/toscawidgets-discuss
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Environment :: Web Environment :: ToscaWidgets
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware
Classifier: Topic :: Software Development :: Widget Sets
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/ 0000755 0001750 0001750 00000000000 11224437421 020213 5 ustar zack zack python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_template.py 0000644 0001750 0001750 00000002051 11175375027 023602 0 ustar zack zack import os
import datetime
from pkg_resources import get_distribution, require
require("PasteScript")
from paste.script.templates import Template, var
class ToscaWidgetsTemplate(Template):
_template_dir = os.path.join(get_distribution('ToscaWidgets').location,
'tw', 'paste_templates', 'widget_template')
summary = "ToscaWidgets widget"
vars = [
var('widget_name', 'Name of the widget package (tw.XXX)'),
var('version', 'Version', default='0.1a0'),
var('description', 'One-line description of the widget'),
var('long_description', 'Multi-line description (in reST)'),
var('author', 'Author name'),
var('author_email', 'Author email'),
var('url', 'URL of homepage'),
var('license_name', 'License name'),
]
def run(self, command, output_dir, vars):
vars['year'] = str(datetime.datetime.now().year)
vars['package'] = vars['widget_name'] or vars['package']
super(ToscaWidgetsTemplate, self).run(command, output_dir, vars)
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/ 0000755 0001750 0001750 00000000000 11224437421 021143 5 ustar zack zack python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/resources.py 0000644 0001750 0001750 00000034113 11175375027 023541 0 ustar zack zack import threading
import logging
import os
import errno
import string
import heapq
import mimetypes
from operator import itemgetter
from itertools import izip, chain, imap
from pkg_resources import resource_filename, working_set, Requirement, \
resource_stream
import tw
from tw.core.base import Widget
from tw.core.util import Enum, OrderedSet, RequestLocalDescriptor
__all__ = [
"Resource", "Link", "JSLink", "CSSLink", "Source", "JSSource", "CSSSource",
"locations", "merge_resources",
"retrieve_resources", "JSFunctionCalls", "IECSSLink", "IECSSSource",
"IEJSLink", "IEJSSource", "JSMixin", "CSSMixin"
]
log = logging.getLogger(__name__)
from webob import Request, Response
class ResourcesApp(object):
def __init__(self, prefix='/resources', bufsize=4*1024):
self._lock = threading.Lock()
self._dirs = []
self.prefix = prefix
self.bufsize = bufsize
def _is_registered(self, webdir, dirname):
for old_wd, old_dn in self:
if webdir == old_wd:
if dirname != old_dn:
raise ValueError("%s is already regsitered for %s" %
(webdir, old_dn))
else:
return True
return False
def register(self, modname, filename):
if isinstance(modname, Requirement):
modname = os.path.basename(working_set.find(modname).location)
basename = os.path.basename(filename)
dirname = os.path.dirname(filename)
parts = ['', modname] + filter(None, dirname.split('/'))
webdir = '/'.join(parts)
self._lock.acquire()
try:
if not self._is_registered(webdir, dirname):
heapq.heappush(self._dirs, (len(webdir), (webdir, dirname)))
log.debug("Regsitered %s at %s", dirname, webdir)
finally:
self._lock.release()
url = '/'.join([self.prefix, webdir.strip('/'), basename])
return webdir, dirname, url
def get_prefixed(self):
return tuple((self.prefix + k, v) for k,v in self)
def __iter__(self):
return imap(itemgetter(1), heapq.nlargest(len(self._dirs), self._dirs))
def __call__(self, environ, start_response):
req = Request(environ)
path_info = req.path_info
resp = self.serve_file(req)
resp = resp or Response(status="404 Not Found")
return resp(environ, start_response)
def serve_file(self, req):
stream, ct, enc = self.get_stream_type_encoding(req.path_info)
if stream:
resp = Response(request=req, app_iter=stream, content_type=ct)
if enc:
resp.content_type_params['charset'] = enc
expires = int(req.environ.get('toscawidgets.resources_expire', 0))
resp.cache_expires(expires)
return resp
else:
return Response(status="404 Not Found")
def is_resource(self, path_info):
for webdir, dirname in self:
if path_info.startswith(webdir):
return True
return False
def get_stream_type_encoding(self, path_info):
if not self.is_resource(path_info):
return None, None, None
parts = filter(None, path_info.split('/'))
modname, relative_path = parts[0], '/'.join(parts[1:])
try:
stream = resource_stream(modname, relative_path)
ct, enc = mimetypes.guess_type(os.path.basename(relative_path))
stream = _FileIter(stream, self.bufsize)
except IOError, e:
# For some reason pkg_resources sometimes sets errno to 0
# when resource can't be found
if e.errno != 0 and e.errno != errno.ENOENT:
raise
stream, ct, enc = None, None, None
return stream, ct, enc
class _FileIter(object):
def __init__(self, fileobj, bufsize):
self.fileobj = fileobj
self.bufsize = bufsize
def __iter__(self):
return self
def next(self):
buf = self.fileobj.read(self.bufsize)
if not buf:
raise StopIteration
return buf
def close(self):
self.fileobj.close()
registry = ResourcesApp()
#------------------------------------------------------------------------------
# Base class for all resources
#------------------------------------------------------------------------------
class Resource(Widget):
"""
A resource for your widget, like a link to external JS/CSS or inline
source to include at the page the widget is displayed.
It has the following parameters:
`location`
Location on the page where the resource should be placed. Available
locations can be queried at ``Resource.valid_locations``
"""
valid_locations = Enum('head','headbottom', 'bodytop', 'bodybottom')
location = valid_locations.head
def add_for_location(self, location):
return location == self.location
def inject(self):
"""
Push this resource into request-local so it is injected to the page
"""
tw.framework.register_resources(self.retrieve_resources())
def register_resources(self):
# A Resource is registered by other widgets, not by itself.
pass
locations = Resource.valid_locations
#------------------------------------------------------------------------------
# Utility Mixins
#------------------------------------------------------------------------------
class CSSMixin:
params = ["media"]
media = "all"
def post_init(self, *args, **kw):
self._resources.add(self)
class JSMixin:
def post_init(self, *args, **kw):
self._resources.add(self)
class IEMixin:
params = ["version"]
version = ''
_trans_table = ( ('>=', '>', '<=', '<'), ('gte ', 'gt ', 'lte ', 'lt '))
def _extend_template(self, d):
d.version = str(d.version)
for i, s in enumerate(self._trans_table[0]):
d.version = d.version.replace(s, self._trans_table[1][i])
s = ('', ' ')[int(bool(d.version))]
d.template = ""%(s,self.template)
#------------------------------------------------------------------------------
# Links
#------------------------------------------------------------------------------
class Link(Resource):
"""
A link to an external resource, like a a JS or CSS file stored in the
filesystem.
Widgets automatically use the framework to register the directory where the
resource is located so be careful that those directories contains no
private data!
"""
params = {
'link': 'Use this to specify an external link. If provided this will '\
'be used as-is as the resources URL. modname and filename '\
'will be ignored.',
'filename': "The relative path (from the module's or distribution's "\
"path) of the file the Link should link to.",
'modname': "The module that contains the Widget declaration. "\
"If not given, it defaults to the name of the module where "\
"the Link is declared. Must be an existent module name. "\
"You can also pass a pkg_resources.Requirement instance to "\
"point to the root of an egg distribution."
}
_link = None
filename = None
modname = None
def __init__(self, *args, **kw):
super(Link, self).__init__(*args, **kw)
if not self.is_external:
modname = self.modname or self.__module__
self.webdir, self.dirname, self.link = registry.register(
modname, self.filename
)
else:
self.link = kw.get('link')
@property
def is_external(self):
return not bool(self.filename and self.modname)
def _get_link(self):
if self.is_external:
return self._link
return tw.framework.url(self._link or '')
def _set_link(self, link):
self._link = link
link = property(_get_link, _set_link)
def __hash__(self):
return hash(self.link)
def __eq__(self, other):
return getattr(other, "link", None) == self.link
class CSSLink(Link,CSSMixin):
"""
A link to an external CSS file.
"""
template = """\
"""
class IECSSLink(CSSLink, IEMixin):
def update_params(self, d):
CSSLink.update_params(self, d)
self._extend_template(d)
class JSLink(Link, JSMixin):
template = """"""
class IEJSLink(JSLink, IEMixin):
def update_params(self, d):
JSLink.update_params(self, d)
self._extend_template(d)
#------------------------------------------------------------------------------
# Raw source Resources
#------------------------------------------------------------------------------
class Source(Resource):
"""
An inlined chunk of source code
Examples::
>>> class MySource(Source):
... template = "$src"
... src = "foo=$foo"
... source_vars = ["foo"]
... foo = "bar"
...
>>> s = MySource()
>>> s.render()
u'foo=bar'
>>> s = MySource(foo='zoo')
>>> s.render()
u'foo=zoo'
>>> s.render(foo='foo')
u'foo=foo'
The whole source can also be overriden
>>> s.render(src='foo')
u'foo'
"""
params = {
'src': "A string with the source to include between the resource's "\
"tags. Can also be a template for string.Template. Any "\
"attribute listed at ``source_vars`` will be fetched from the "\
"instance or from the kw args to ``display`` or ``render`` "\
"into a dictionary to provide values to fill in."
}
def __new__(cls, *args, **kw):
"""Support positional params. (src)"""
src = None
parent = None
if len(args) > 0:
src = args[0]
kw.setdefault('src', src or getattr(cls, 'src', None))
if len(args) > 1:
parent = args[1]
return Resource.__new__(cls, None, parent, [], **kw)
def update_params(self,d):
super(Source, self).update_params(d)
src = d.get('src')
if src:
source_vars = dict(
v for v in [(k, getattr(self,k,None)) for k in self.source_vars]
)
source_vars.update(
v for v in d.iteritems() if v[0] in self.source_vars
)
d['src'] = string.Template(src).safe_substitute(**source_vars)
def __hash__(self):
return hash(self.src)
def __eq__(self, other):
return self.src == getattr(other, "src", None)
class CSSSource(Source, CSSMixin):
"""
An inlined chunk of CSS source code.
"""
template = """"""
class IECSSSource(CSSSource, IEMixin):
def update_params(self, d):
super(IECSSSource, self).update_params(d)
self._extend_template(d)
class JSSource(Source, JSMixin):
"""
An inlined chunk of JS source code.
"""
template = """"""
class IEJSSource(JSSource, IEMixin):
def update_params(self, d):
JSSource.update_params(self, d)
self._extend_template(d)
class JSFunctionCalls(JSSource):
params = ["function_calls"]
function_calls = []
def __init__(self, id=None, parent=None, children=[], **kw):
super(JSFunctionCalls, self).__init__(id, parent, children, **kw)
self.src = "\n%s\n" % "\n".join(map(str, self.function_calls))
class JSDynamicFunctionCalls(JSFunctionCalls):
params = ["call_getter"]
call_getter = lambda s, location: []
def update_params(self,d):
super(JSDynamicFunctionCalls,self).update_params(d)
# Keep in mind self._calls_for_request has calls for *all* widgets
d.src = "\n%s\n" % "\n".join(
map(str, chain(self.call_getter(self.location), d.function_calls))
)
# Since our src is generated dynamically base hash and equality on id
def __hash__(self):
return id(self)
def __eq__(self, other):
return id(self) == id(other)
# Utilities to retrieve resources
def merge_resources(to, from_):
"""
In-place merge all resources from ``from_`` into ``to``. Resources
from ``to_`` will come first in each resulting OrderedSet.
"""
for k in locations:
from_location = from_.get(k)
if from_location:
to.setdefault(k, OrderedSet()).add_all(from_location)
return to
def retrieve_resources(obj):
"""Recursively retrieve resources from obj"""
ret = {}
if getattr(obj, 'retrieve_resources', None):
ret = obj.retrieve_resources()
elif getattr(obj, 'itervalues', None):
ret = retrieve_resources(obj.itervalues())
elif getattr(obj, '__iter__', None):
ret = reduce(merge_resources, imap(retrieve_resources, iter(obj)), {})
return ret
class DynamicCalls(object):
_calls_for_request = RequestLocalDescriptor('_calls_for_request')
def __init__(self):
self.call_widgets = {}
for l in locations:
#XXX A circular-ref is probably created here with 'call_getter' but
# since we're a module-level singleton we don't care much
w = JSDynamicFunctionCalls('dynamic_js_calls_for_'+l, location=l,
call_getter=self._get_calls_for_request)
self.call_widgets[l] = w
def reset(self):
del self._calls_for_request
def inject_call(self, call, location="bodybottom"):
self._get_calls_for_request(location).append(call)
self.call_widgets[location].inject()
def _get_calls_for_request(self, location):
try:
self._calls_for_request
except AttributeError:
log.debug("Initializing calls for request")
self._calls_for_request = dict((l,[]) for l in locations)
return self._calls_for_request[location]
dynamic_js_calls = DynamicCalls()
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/testutil.py 0000644 0001750 0001750 00000011154 11175375027 023404 0 ustar zack zack import sys
import doctest
from new import instancemethod
from glob import glob
from unittest import TestCase
from itertools import imap, chain
from tw.core.util import install_framework
import pkg_resources
__all__ = [
"RequireMixin",
"WidgetMixin",
"WidgetTestCase",
"WidgetRequireTestCase",
"get_doctest_suite",
]
class RequireMixin(object):
"""
Doesn't run the tests in the TestCases that inherit from this mixin
class if the package requisites in 'require' are not met.
"""
require = []
def __init__(self, *args, **kw):
try:
pkg_resources.require(*self.require)
except pkg_resources.DistributionNotFound:
name = ':'.join([self.__class__.__module__, self.__class__.__name__])
reqs = self.require
self._message_displayed = False
def dummy_run(self, result=None):
if not self._message_displayed:
print >> sys.stderr, "Skipping all tests in %s due to missing " \
"requirements: %r" % (name, reqs)
self._message_displayed = True
self.run = instancemethod(dummy_run, self, self.__class__)
TestCase.__init__(self, *args, **kw)
class WidgetMixin(object):
widget_kw = {}
def setUp(self):
install_framework(force=True)
if hasattr(self, 'TestWidget'):
self.widget = self.TestWidget('test', **self.widget_kw)
def tearDown(self):
if hasattr(self, 'TestWidget'):
del self.widget
def assertInOutput(self, strings, *args, **kw):
output = self.widget.render(*args, **kw)
if isinstance(strings, basestring):
strings = [strings]
for s in strings:
self.failUnless(s in output, "%s\n\n%r not in output" %(output,s))
def assertInOutputIC(self, strings, *args, **kw):
output = self.widget.render(*args, **kw).lower()
if isinstance(strings, basestring):
strings = [strings]
for s in strings:
s = s.lower()
self.failUnless(s in output, "%s\n\n%r not in output" %(output,s))
def assertNotInOutput(self, strings, *args, **kw):
output = self.widget.render(*args, **kw)
if isinstance(strings, basestring):
strings = [strings]
for s in strings:
self.failUnless(
s not in output, "%s\n\n%r in output" %(output,s)
)
def assertNotInOutputIC(self, strings, *args, **kw):
output = self.widget.render(*args, **kw).lower()
if isinstance(strings, basestring):
strings = [strings]
for s in strings:
s = s.lower()
self.failUnless(
s not in output, "%s\n\n%r in output" %(output,s)
)
def assertInStaticCalls(self, strings):
"""Asserts given strings are included in the widget's static
js calls."""
from tw.core.resources import JSFunctionCalls
calls = JSFunctionCalls(function_calls=self.widget._js_calls)
output = calls.render()
if isinstance(strings, basestring):
strings = [strings]
for s in strings:
self.failUnless(
s in output, "%s\n\n%r not in static calls" %(output,s)
)
def assertInDynamicCalls(self, strings, *args, **kw):
"""Asserts given strings are included in the widget's dynamic
js calls."""
from tw.core.resources import dynamic_js_calls
location = kw.pop('location', 'bodybottom')
self.widget.render(*args, **kw)
output = dynamic_js_calls.call_widgets[location].render()
if isinstance(strings, basestring):
strings = [strings]
for s in strings:
self.failUnless(
s in output, "%s\n\n%r not in dynamic calls" %(output,s)
)
class WidgetTestCase(WidgetMixin, TestCase):
pass
class WidgetRequireTestCase(RequireMixin, WidgetTestCase):
pass
def get_doctest_suite(doctest_files, doctest_modules):
doctest_files = chain(*(imap(glob, doctest_files)))
suite = doctest.DocFileSuite(
*tuple(doctest_files),
**{'optionflags':doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE,
'module_relative':False,
}
)
for mod in doctest_modules:
try:
suite.addTests(doctest.DocTestSuite(
mod,
**{'optionflags':doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE}
))
except ValueError:
pass # Mod has probably no doctests... ignore it
return suite
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/js.py 0000644 0001750 0001750 00000016241 11175375027 022145 0 ustar zack zack """
Python-JS interface to dynamically create JS function calls from your widgets.
This moudle doesn't aim to serve as a Python-JS "translator". You should code
your client-side code in JavaScript and make it available in static files which
you include as JSLinks or inline using JSSources. This module is only intended
as a "bridge" or interface between Python and JavaScript so JS function
**calls** can be generated programatically.
"""
import sys
import logging
from itertools import imap
import simplejson.encoder
__all__ = ["js_callback", "js_function", "js_symbol", "encode"]
log = logging.getLogger(__name__)
class TWEncoder(simplejson.encoder.JSONEncoder):
"""A JSON encoder that can encode Widgets, js_calls, js_symbols and
js_callbacks.
Example::
>>> encode = TWEncoder().encode
>>> print encode({'onLoad': js_function("do_something")(js_symbol("this"))})
{"onLoad": do_something(this)}
>>> from tw.api import Widget
>>> w = Widget("foo")
>>> args = {'onLoad': js_callback(js_function('jQuery')(w).click(js_symbol('onClick')))}
>>> print encode(args)
{"onLoad": function(){jQuery(\\"foo\\").click(onClick)}}
>>> print encode({'args':args})
{"args": {"onLoad": function(){jQuery(\\"foo\\").click(onClick)}}}
"""
def __init__(self, *args, **kw):
self.pass_through = (_js_call, js_callback, js_symbol, js_function)
super(TWEncoder, self).__init__(*args, **kw)
def default(self, obj):
if isinstance(obj, self.pass_through):
return self.mark_for_escape(obj)
elif hasattr(obj, '_id'):
return str(obj.id)
return super(TWEncoder, self).default(obj)
def encode(self, obj):
encoded = super(TWEncoder, self).encode(obj)
return self.unescape_marked(encoded)
def mark_for_escape(self, obj):
return '*#*%s*#*' % obj
def unescape_marked(self, encoded):
return encoded.replace('"*#*','').replace('*#*"', '')
class js_symbol(object):
def __init__(self, name):
self._name = name
def __str__(self):
return str(self._name)
class js_callback(object):
"""A js function that can be passed as a callback to be called
by another JS function
Examples:
.. sourcecode:: python
>>> str(js_callback("update_div"))
'update_div'
>>> str(js_callback("function (event) { .... }"))
'function (event) { .... }'
# Can also create callbacks for deferred js calls
>>> str(js_callback(js_function('foo')(1,2,3)))
'function(){foo(1, 2, 3)}'
# Or equivalently
>>> str(js_callback(js_function('foo'), 1,2,3))
'function(){foo(1, 2, 3)}'
# A more realistic example
>>> jQuery = js_function('jQuery')
>>> my_cb = js_callback('function() { alert(this.text)}')
>>> on_doc_load = jQuery('#foo').bind('click', my_cb)
>>> call = jQuery(js_callback(on_doc_load))
>>> print call
jQuery(function(){jQuery(\\"#foo\\").bind(\\"click\\", function() { alert(this.text)})})
"""
def __init__(self, cb, *args):
if isinstance(cb, basestring):
self.cb = cb
elif isinstance(cb, js_function):
self.cb = "function(){%s}" % cb(*args)
elif isinstance(cb, _js_call):
self.cb = "function(){%s}" % cb
else:
self.cb = ''
def __call__(self, *args):
raise TypeError("A js_callback cannot be called from Python")
def __str__(self):
return self.cb
class js_function(object):
"""A JS function that can be "called" from python and and added to
a widget by widget.add_call() so it get's called every time the widget
is rendered.
Used to create a callable object that can be called from your widgets to
trigger actions in the browser. It's used primarily to initialize JS code
programatically. Calls can be chained and parameters are automatically
json-encoded into something JavaScript undersrtands. Example::
.. sourcecode:: python
>>> jQuery = js_function('jQuery')
>>> call = jQuery('#foo').datePicker({'option1': 'value1'})
>>> str(call)
'jQuery("#foo").datePicker({"option1": "value1"})'
Calls are added to the widget call stack with the ``add_call`` method.
If made at Widget initialization those calls will be placed in
the template for every request that renders the widget.
.. sourcecode:: python
>>> from tw.api import Widget
>>> class SomeWidget(Widget):
... params = ["pickerOptions"]
... pickerOptions = {}
... def __init__(self, *args, **kw):
... super(SomeWidget, self).__init__(*args, **kw)
... self.add_call(
... jQuery('#%s' % self.id).datePicker(self.pickerOptions)
... )
If we want to dynamically make calls on every request, we ca also add_calls
inside the ``update_params`` method.
.. sourcecode:: python
>>> class SomeWidget(Widget):
... params = ["pickerOptions"]
... pickerOptions = {}
... def update_params(self, d):
... super(SomeWidget, self).update_params(d)
... self.add_call(
... jQuery('#%s' % d.id).datePicker(d.pickerOptions)
... )
This would allow to pass different options to the datePicker on every
display.
JS calls are rendered by the same mechanisms that render required css and
js for a widget and places those calls at bodybottom so DOM elements which
we might target are available.
Examples:
.. sourcecode:: python
>>> call = js_function('jQuery')("a .async")
>>> str(call)
'jQuery("a .async")'
# js_function calls can be chained:
>>> call = js_function('jQuery')("a .async").foo().bar()
>>> str(call)
'jQuery("a .async").foo().bar()'
"""
def __init__(self, name):
self.__name = name
def __call__(self, *args):
return _js_call(self.__name, [], args, called=True)
class _js_call(object):
__slots__ = ('__name', '__call_list', '__args', '__called')
def __init__(self, name, call_list, args=None, called=False):
self.__name = name
self.__args = args
call_list.append(self)
self.__call_list = call_list
self.__called = called
def __getattr__(self, name):
return self.__class__(name, self.__call_list)
def __call__(self, *args):
self.__args = args
self.__called = True
return self
def __get_js_repr(self):
if self.__called:
args = self.__args
return '%s(%s)' % (self.__name, ', '.join(imap(encode, args)))
else:
return self.__name
def __str__(self):
if not self.__called:
raise TypeError('Last element in the chain has to be called')
return '.'.join(c.__get_js_repr() for c in self.__call_list)
def __unicode__(self):
return str(self).decode(sys.getdefaultencoding())
encode = TWEncoder().encode
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/meta.py 0000644 0001750 0001750 00000010750 11175375027 022456 0 ustar zack zack import inspect
from pkg_resources import iter_entry_points
from tw.core.util import pre_post_hooks
from tw.core.exceptions import *
__all__ = [ "WidgetType", "WidgetsList"]
class WidgetType(type):
def __new__(meta,name,bases,dct):
dct['_cls_children'] = dct.pop('children',_children_from_bases(bases))
if isinstance(dct.get('params'), dict):
for param_name, doc in dct['params'].iteritems():
dct[param_name+'__doc'] = doc
params = frozenset_from_all_bases(dct,bases,'params')
frozenset_from_all_bases(dct,bases,'source_vars')
__init__ = dct.pop('__init__', None)
if __init__:
dct['__init__'] = pre_post_hooks(None, 'post_init')(__init__)
new = type.__new__(meta,name,bases,dct)
return new
@classmethod
def iter_classes(meta):
"""Iterates over all the Widget subclasses in the modules
that are declared as `toscawidgets.widgets` entrypoints
>>> from tw.api import Widget
>>> len(list(Widget.iter_classes())) > 0
True
"""
seen = set()
for ep in iter_entry_points('toscawidgets.widgets'):
try:
mod = ep.load(False)
except ImportError, e:
continue
for name in dir(mod):
obj = getattr(mod, name)
if isinstance(obj, meta) and obj not in seen:
seen.add(obj)
yield obj
def _children_from_bases(bases):
for base in bases:
if hasattr(base, '_cls_children'):
return base._cls_children
return []
def frozenset_from_all_bases(clsdct, bases, name):
_set = set(clsdct.pop(name,[]))
[_set.update(getattr(b,name)) for b in bases if hasattr(b, name)]
fs = clsdct[name] = frozenset(_set)
return fs
class WidgetsListType(type):
def __new__(meta,name,bases,dct):
clones = []
for id, w in dct.items():
if hasattr(w,'_serial') and hasattr(w, 'clone'):
dct.pop(id)
clones.append((w._serial, id, w.clone) )
clones.sort()
def __init__(self, clones=clones):
# we instantiate the clones on initialization
widgets = [w[2](id=w[1]) for w in clones]
self.extend(widgets)
dct.update({'__slots__':[], '__init__':__init__})
return type.__new__(meta,name,bases,dct)
def __add__(self, other):
if isinstance(self, list) and isinstance(other,list):
return list.__add__(self,other)
elif isinstance(self, list) and inspect.isclass(other):
return list.__add__(self,other())
elif inspect.isclass(self) and isinstance(other,list):
return list.__add__(self(),other)
elif inspect.isclass(self) and inspect.isclass(other):
return list.__add__(self(),other())
def __radd__(self, other):
if isinstance(self, list) and isinstance(other,list):
return list.__add__(other,self)
elif isinstance(self, list) and inspect.isclass(other):
return list.__add__(other(),self)
elif inspect.isclass(self) and isinstance(other,list):
return list.__add__(other,self())
elif inspect.isclass(self) and inspect.isclass(other):
return list.__add__(other(),self())
class WidgetsList(list):
"""
Syntactic sugar for declaring a list of widgets.
>>> from tw.api import Widget
>>> class Widgets(WidgetsList):
... a = Widget()
... b = Widget()
... c = Widget()
...
>>> widgets = Widgets()
>>> [w.id for w in widgets]
['a', 'b', 'c']
WidgetsLists can be passed to another widget as children by
the instance or the class.
>>> w = Widget('foo', children=widgets)
>>> [c.id for c in w.children]
['foo_a', 'foo_b', 'foo_c']
>>> w = Widget('foo', children=Widgets)
>>> [c.id for c in w.children]
['foo_a', 'foo_b', 'foo_c']
WidgetsLists subclasses can also be added to reuse common widgets
>>> class Widgets2(WidgetsList):
... d = Widget()
...
>>> widgets = Widgets + Widgets2
>>> [w.id for w in widgets]
['a', 'b', 'c', 'd']
>>> widgets = Widgets2 + Widgets
>>> [w.id for w in widgets]
['d', 'a', 'b', 'c']
"""
__metaclass__ = WidgetsListType
if __name__ == "__main__":
import doctest
doctest.testmod()
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/mako_util.py 0000644 0001750 0001750 00000002446 11217773107 023515 0 ustar zack zack import unicodedata
from mako.runtime import Undefined
from cgi import escape
#from mako.filters import xml_escape
__all__ = ["attrs", "content"]
_BOOLEAN_ATTRS = frozenset(['selected', 'checked', 'compact', 'declare',
'defer', 'disabled', 'ismap', 'multiple',
'nohref', 'noresize', 'noshade', 'nowrap'])
def attrs(context, args=None, attrs=None):
# Emulates Genshi's AttrsDirective (poorly)
if isinstance(args, dict):
args = args.items()
if not args:
args = []
else:
args = args[:]
if attrs:
args.extend(attrs.items())
bools = _BOOLEAN_ATTRS
return u" ".join([u'%s="%s"' % (k, escape(unicode(k in bools and k or v), True))
for k,v in args
if (k not in bools and v is not None) or (k in bools and v)])
def content(context, value):
if value is None:
return ""
else:
return escape(unicode(value))
def safe_str(context, value):
"""Converts value to its string representation, if unicode it makes it ascii
safe by converting characters above 128 to their <128 equivalents."""
if isinstance(value, unicode):
return ''.join(unicodedata.normalize("NFD",c)[0] for c in value)
else:
return str(value)
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/command.py 0000644 0001750 0001750 00000026316 11175375027 023153 0 ustar zack zack import errno
import re
import operator
import shutil
import sys
import os
import tempfile
import subprocess
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
import pkg_resources
from setuptools import Command
from tw.core.resources import registry
class archive_tw_resources(Command):
"""Setuptools command to copy and optionally compress all static resources
from a series of distributions and their dependencies into a directory
where they can be served by a fast web server.
To enable compression of CSS and JS files you will need to have installed a
Java Runtime Environment and YUICompressor
(http://www.julienlecomte.net/yuicompressor)
In order for resources from widget eggs to be properly collected these
need to have a 'toscawidgets.widgets' 'widgets' entry-point which points
to a module which, when imported, instantiates all needed JS and CSS Links.
The result is laid out in the output directory in such a way that when
a a web server such as Apache or Nginx is configured to map URLS that
begin with /toscawidgets to that directory static files will be served
from there bypassing python completely.
To integrate this command into your build process you can add these lines
to ``setup.cfg``::
[archive_tw_resources]
output = /home/someuser/public_html/toscawidgets/
compresslevel = 2
distributions = MyProject
yuicompressor = /home/someuser/bin/yuicompressor.jar
onepass = true
[aliases]
deploy = archive_tw_resources --force install
This way you can run::
$ python setup.py deploy
To install a new version of your app and copy/compress resources.
"""
description = "Copies ToscaWidgets static resources into a directory where"\
" a fast web-server can serve them."
user_options = [
("output=", "o",
"Output directory. If it doesn't exist it will be created."),
("force", "f", "If output dir exists, it will be ovewritten"),
("onepass", None, "If given, yuicompressor will only be called once "\
"for each kind of file with a all files "\
"together and then separated back into smaller "\
"files"),
("compresslevel=", "c",
"Compression level: 0) for no compression (default). "\
"1) for js-minification. "\
"2) for js & css compression"),
("yuicompressor=", None, "Name of the yuicompressor jar."),
("distributions=", "d",
"List of widget dists. to include resources from "
"(dependencies will be handled recursively). Note that "
"these distributions need to define a 'toscawidgets.widgets' "
"'widgets' entrypoint pointing to a a module where "
"resources are located."),
]
def initialize_options(self):
self.output = ''
self.force = False
self.onepass = False
self.compresslevel = 0
self.distributions = []
self.yuicompressor = 'yuicompressor.jar'
def finalize_options(self):
self.ensure_string("output")
self.ensure_string("yuicompressor")
self.ensure_string_list("distributions")
self.compresslevel = int(self.compresslevel)
self.yuicompressor = os.path.abspath(self.yuicompressor)
def run(self):
if not self.output:
print >> sys.stderr, "Need to specify an output directory"
return
if not self.distributions:
print >> sys.stderr, "Need to specify at least one distribution"
return
if os.path.exists(self.output) and not self.force:
print >> sys.stderr, ("Destination dir %s exists. " % self.output)+\
"Use -f to ovewrite"
return
if self.compresslevel > 0 and not os.path.exists(self.yuicompressor):
print >> sys.stderr, "Could not find YUICompressor at " + \
self.yuicompressor
return
tempdir = tempfile.mktemp()
self.execute(os.makedirs, (tempdir,), "Creating temp dir %s" % tempdir)
if self.compresslevel > 0:
if self.onepass:
self.writer = OnePassCompressingWriter(self, tempdir)
else:
self.writer = CompressingWriter(self, tempdir)
else:
self.writer = FileWriter(self, tempdir)
self.execute(self._copy_resources, tuple(), "Extracting resources")
self.writer.finalize()
if os.path.exists(self.output):
self.execute(shutil.rmtree, (self.output,),
"Deleting old output dir %s" % self.output)
self.execute(os.makedirs, (self.output,), "Creating output dir")
final_dest = os.path.join(self.output, registry.prefix.strip('/'))
self.execute(shutil.move, (tempdir, final_dest),
"Moving build to %s" % final_dest)
def _load_widgets(self, distribution):
try:
requires = [r.project_name for r in
pkg_resources.get_distribution(distribution).requires()]
map(self._load_widgets, requires)
mod = pkg_resources.load_entry_point(distribution,
'toscawidgets.widgets',
'widgets')
self.announce("Loaded %s" % mod.__name__)
except ImportError:
self.announce("%s has no widgets entrypoint" % distribution)
def _copy_resources(self):
map(self._load_widgets, self.distributions)
for webdir, dirname in registry:
parts = filter(None, webdir.split('/'))
modname = parts[0]
fname = '/'.join(parts[1:])
self.execute(self._copy_resource_tree, (modname, fname),
"Copying %s recursively into %s" %
(dirname, self.writer.base))
def _copy_resource_tree(self, modname, fname):
try:
for name in pkg_resources.resource_listdir(modname, fname):
name = '/'.join((fname, name))
rel_name = '/'.join((modname, name))
if pkg_resources.resource_isdir(modname, name):
self.execute(self._copy_resource_tree, (modname, name),
"Recursing into " + rel_name)
else:
stream = pkg_resources.resource_stream(modname, name)
filename = '/'.join((modname, name))
self.execute(self.writer.write_file, (stream, filename),
"Processing " + filename)
stream.close()
except OSError, e:
if e.errno == errno.ENOENT:
self.warn("Could not copy %s" % repr((modname, fname, e)))
class FileWriter(object):
def __init__(self, cmd, base):
self.base = base
self.cmd = cmd
def finalize(self):
pass
def write_file(self, stream, path):
final = os.path.join(self.base, path)
if not os.path.exists(os.path.dirname(final)):
os.makedirs(os.path.dirname(final))
dest = open(final, 'wb')
self.announce("Writting %s" % path)
shutil.copyfileobj(stream, dest)
dest.close()
# Delegate methods to Command
for name in "warn announce error execute".split():
exec """\
def %(name)s(self, *args, **kw):
return self.cmd.%(name)s(*args, **kw)
""" % locals()
class CompressingWriter(FileWriter):
def __init__(self, *args, **kw):
super(CompressingWriter, self).__init__(*args, **kw)
self.counters = 0, 0
def finalize(self):
try:
avg = reduce(operator.truediv, self.counters) * 100
msg = "Total JS&CSS compressed size is %.2f%% of original" % avg
self.announce(msg)
except ZeroDivisionError:
# No files were compressed
pass
def compress(self, stream, path):
typ = path.split('.')[-1]
if typ not in ('css', 'js'):
return stream
args = ['java', '-jar', self.cmd.yuicompressor, '--type', typ]
if self.cmd.compresslevel < 2:
args.append('--nomunge')
args.append('--charset=utf8')
p = subprocess.Popen(args, stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE)
self.announce("Compressing %s" % path)
buffer = StringIO()
shutil.copyfileobj(stream, buffer)
data = buffer.getvalue()
if not data:
return buffer
stdout, stderr = p.communicate(data)
if p.returncode != 0:
self.warn("Failed to compress %s: %d" % (path, p.returncode))
self.warn("File will be copied untouched")
sys.stderr.write(stderr)
sys.stderr.write(stdout)
stream.seek(0)
else:
count = len(stdout), len(data)
ratio = reduce(operator.truediv, count)
self.counters = map(sum, zip(self.counters, count))
msg = "Compressed %s (New size: %.2f%%)" % (path, ratio*100)
self.announce(msg)
stream = StringIO(stdout)
return stream
def write_file(self, stream, path):
stream = self.compress(stream, path)
return super(CompressingWriter, self).write_file(stream, path)
class OnePassCompressingWriter(CompressingWriter):
def __init__(self, *args, **kw):
super(OnePassCompressingWriter, self).__init__(*args, **kw)
#XXX This comment trick only works with JS as of YUICompressor 2.3.5
self._caches = {'js': StringIO()}
self._marker = "/*! MARKER #### %(path)s #### MARKER */"
regexp = r"^\/\* MARKER #### (?P.*?) #### MARKER \*\/$"
self._re = re.compile(regexp)
def _demultiplex(self, stream):
cur_file = None
buffer = StringIO()
stream.seek(0)
for line in stream:
m = self._re.match(line)
if m:
if cur_file:
buffer.seek(0)
FileWriter.write_file(self, buffer, cur_file)
buffer.truncate(0)
cur_file = m.group('path')
else:
buffer.write(line)
def finalize(self):
self.announce("Compressing all defered files")
for typ, cache in self._caches.iteritems():
cache.seek(0)
# self.compress only wants to know the file extension to see
# what kind of file it is, we pass a dummy one
compressed = self.compress(cache, '__defered__.'+typ)
self._demultiplex(compressed)
super(OnePassCompressingWriter, self).finalize()
def write_file(self, stream, path):
typ = path.split('.')[-1]
cache = self._caches.get(typ)
if not cache:
self.announce("Will not consider %s for onepass" % path)
return CompressingWriter.write_file(self, stream, path)
print >> cache, self._marker % locals()
self.announce("Defering %s for compression in one pass" % path)
shutil.copyfileobj(stream, cache)
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/util.py 0000644 0001750 0001750 00000040065 11211320500 022460 0 ustar zack zack import inspect
import re
import sys
import warnings
import time
import weakref
from itertools import count, izip
__all__ = [
"OrderedSet",
"RequestLocalDescriptor",
"lazystring",
"asbool",
"LRUCache",
"disable_runtime_checks",
]
# Stolen from PasteDeploy
def asbool(obj):
if isinstance(obj, (str, unicode)):
obj = obj.strip().lower()
if obj in ['true', 'yes', 'on', 'y', 't', '1']:
return True
elif obj in ['false', 'no', 'off', 'n', 'f', '0']:
return False
else:
raise ValueError(
"String is not true/false: %r" % obj)
return bool(obj)
def assert_bool_attr(name, state, exc):
"""
Raises 'exc' if given flag is not equal to 'state'.
"""
def entangle(func):
def wrapper(self, *args, **kw):
if getattr(self,name) == state:
return func(self, *args, **kw)
raise exc
wrapper.func_name = func.func_name
wrapper.__dict__ = func.__dict__.copy()
return wrapper
return entangle
def pre_post_wrapper(pre=None, post=None, lock=None):
"""
Decorates a method excecuting pre and post methods around it.
Can be used to decorate the same method in different subclasses and takes
care that pre is executed only once at the first cooperative call and post
once at the end of the cooperative call-chain.
>>> entries = 0
>>> exits = 0
>>> def pre(*args, **kw): global entries; entries += 1
>>> def post(*args, **kw): global exits; exits += 1
>>> class A(object):
... @pre_post_wrapper(pre, post)
... def say_name(self, name):
... print name
>>> class B(A):
... @pre_post_wrapper(pre, post)
... def say_name(self, name):
... super(B, self).say_name(name)
... print name
>>> class C(B):
... @pre_post_wrapper(pre, post)
... def say_name(self, name):
... super(C, self).say_name(name)
... print name
>>> c = C()
>>> c.say_name('foo')
foo
foo
foo
>>> entries
1
>>> exits
1
A reentrant lock can be passed to syncronize the wrapped method. It is a
must if the instance is shared among several threads.
"""
def entangle(func):
def wrapper(self, *args, **kw):
counter_name = '__%s_wrapper_counter' % func.func_name
if lock:
lock.aquire()
try:
counter = getattr(self, counter_name, 0) + 1
setattr(self, counter_name, counter)
if counter == 1 and pre:
pre(self, *args, **kw)
output = func(self, *args, **kw)
counter = getattr(self, counter_name)
setattr(self, counter_name, counter - 1)
if counter == 1:
delattr(self, counter_name)
if post: post(self, *args, **kw)
finally:
if lock:
lock.release()
return output
wrapper.func_name = func.func_name
wrapper.__dict__ = func.__dict__.copy()
return wrapper
return entangle
def pre_post_hooks(pre_name=None, post_name=None, lock=None):
def entangle(func):
def wrapper(self, *args, **kw):
counter_name = '__%s_wrapper_counter' % func.func_name
bases = list(inspect.getmro(self.__class__))
if lock:
lock.aquire()
try:
counter = getattr(self, counter_name, 0) + 1
setattr(self, counter_name, counter)
if counter == 1 and pre_name:
for base in bases:
try:
# make sure we use the hook defined in base
base.__dict__[pre_name](self, *args, **kw)
except KeyError:
pass
output = func(self, *args, **kw)
counter = getattr(self, counter_name)
setattr(self, counter_name, counter - 1)
if counter == 1:
delattr(self, counter_name)
if post_name:
for base in bases:
try:
base.__dict__[post_name](self, *args, **kw)
except KeyError:
pass
finally:
if lock:
lock.release()
return output
wrapper.func_name = func.func_name
wrapper.__dict__ = func.__dict__.copy()
return wrapper
return entangle
class CachedInspect(object):
"""
In general "inspect" calls are extremely expensive. However, if we cache them
on an object by object basis, we should be able to speed things up a
"""
def __init__(self):
self.functions = weakref.WeakKeyDictionary()
self.methods = weakref.WeakKeyDictionary()
self.argspec = weakref.WeakKeyDictionary()
def is_function(self, obj):
truth = self.functions.get(obj, None)
if truth is None:
truth = self.functions[obj] = inspect.isfunction(obj)
return truth
def is_method(self, obj):
truth = self.methods.get(obj, None)
if truth is None:
truth = self.methods[obj] = inspect.ismethod(obj)
return truth
def getargspec(self, obj):
spec = self.argspec.get(obj, None)
if spec is None:
spec = self.argspec[obj] = inspect.getargspec(obj)
return spec
callable_cache = CachedInspect()
def callable_wo_args(obj):
if callable(obj) and (callable_cache.is_function(obj) or callable_cache.is_method(obj)):
argspec = callable_cache.getargspec(obj)
args = argspec[0]
defaults = argspec[3]
arg_length = callable_cache.is_method(obj) and 1 or 0
return (
(args is not None and (len(args) == arg_length)) or
(defaults is not None and len(args) == len(defaults))
)
return False
_id_RE = re.compile(r'(\w+)+(?:-(\d))*')
def unflatten_args(child_args):
new = {}
for k,v in child_args.iteritems():
splitted = k.split('.',1)
id = splitted[0]
if len(splitted) == 2:
rest = splitted[1]
if not id:
new[rest] = v
continue
for_id = new.setdefault(id, {})
for_id.setdefault('child_args', {})[rest] = v
else:
for_id = new.setdefault(id,{})
for key, val in v.iteritems():
for_id.setdefault(key,val)
convert = set()
for k,v in new.items():
m = _id_RE.match(k)
if not m:
raise ValueError(
"%r is not a valid id to reference a child" % k
)
id, n = m.groups()
if n is not None:
new.pop(k,None)
convert.add(id)
for_id = new.setdefault(id, {})
for_id[int(n)] = v
for k in convert:
for_k = new[k]
l = []
for n in count():
l.append(for_k.pop(n, {}))
if not for_k: break
new[k] = {'child_args':l}
return new
class OrderedSet(list):
"""Set preserving item order."""
def add(self, item):
if item not in self:
self.append(item)
def add_all(self, iterable):
for item in iterable:
self.add(item)
class _RaiseAttributeError: pass
class ThreadSafeDescriptor(object):
"""Base class for threadsafe widget descriptors."""
class RequestLocalDescriptor(ThreadSafeDescriptor):
"""A descriptor that proxies to tw.framework.request_local for
passing state among widgets in a thread-safe manner for the current request.
Do not abuse this or code can become increasingly unmantainable!
"""
def __init__(self, name, default=_RaiseAttributeError, __doc__=None, qualify_with_id=False):
"""Proxy to request local storage attribute named by ``name``.
If ``default`` is provided no AttributeError will be raised if attribute
does not exist ar request local storage when getting or deleting.
"""
self.name = name
self.default = default
self.qualify_with_id = qualify_with_id
self.__doc__ = __doc__ or "'%s' at request-local storage" % name
def __get__(self, obj, typ=None):
if obj is None:
# If called on Widget class return descriptor
return self
import tw
request_local = tw.framework.request_local
name = self.name
if self.qualify_with_id:
name += "_%i" % id(obj)
try:
return getattr(request_local, name )
except AttributeError:
if self.default is _RaiseAttributeError:
raise
else:
try:
value = self.default()
except TypeError:
value = self.default
setattr(request_local, name, value)
return value
def __set__(self, obj, value):
import tw
request_local = tw.framework.request_local
name = self.name
if self.qualify_with_id:
name += "_%i" % id(obj)
setattr(request_local, name, value)
def __delete__(self, obj):
import tw
request_local = tw.framework.request_local
name = self.name
if self.qualify_with_id:
name += "_%i" % id(obj)
try:
delattr(request_local, name)
except AttributeError:
if self.default is _RaiseAttributeError:
raise
def install_framework(force=False):
import tw
if not hasattr(tw, 'framework') or force:
from tw.core.registry import StackedObjectProxy, Registry
from tw.mods import base
dummy_framework = base.HostFramework()
# start up a dummy request with dummy environ
dummy_registry = Registry()
dummy_registry.prepare()
dummy_framework.start_request({
'SCRIPT_NAME': '',
'toscawidgets.prefix': '/toscawidgets',
'paste.registry' : dummy_registry,
})
tw.framework = StackedObjectProxy(
dummy_framework,
name='ToscaWidgetsFramework',
)
class Enum(dict):
"""Less strict Enum than the one provided by TG"""
def __init__(self, *args):
for arg in args:
self[arg]= arg
def __getattr__(self, name):
try:
return self[name]
except KeyError:
raise AttributeError(name)
class Bunch(dict):
__setattr__ = dict.__setitem__
def __delattr__(self, name):
try:
del self[name]
except KeyError:
raise AttributeError(name)
def __getattr__(self, name):
try:
return self[name]
except KeyError:
raise AttributeError(name)
def make_bunch(d):
"""Converts a dict instance into a Bunch"""
return Bunch(d)
# Adapted form turbogears'
class lazystring(object):
"""Has a number of lazily evaluated functions replicating a string.
"""
def __init__(self, string):
self.string = string
def eval(self):
from tw import framework
return framework.translator(self.string)
def __unicode__(self):
return unicode(self.eval())
def __str__(self):
return str(self.eval())
def __mod__(self, other):
return self.eval() % other
def __cmp__(self, other):
return cmp(self.eval(), other)
def __eq__(self, other):
return self.eval() == other
class MultipleReplacer(object):
"""Performs several regexp substitutions on a string with a single pass.
``dct`` is a dictionary keyed by a regular expression string and with a
callable as value that will get called to produce a subsituted value.
The callable takes the matched text as first argument and may take any
number of positional and keyword arguments. These arguments are any extra
args passed when calling the instance.
For performance, a single regular expression is built.
Example::
>>> string = "aaaabbbcc"
>>> replacer = MultipleReplacer({
... 'a+':lambda g, context: g + context['after_a'],
... 'b+':lambda g, context: g + context['after_b'],
... 'c+':lambda g, context: context['before_c'] + g,
... })
>>> replacer("aaaabbbcc", dict(
... after_a = "1",
... after_b = "2",
... before_c = "3"
... ))
'aaaa1bbb23cc'
"""
def __init__(self, dct, options=0):
self._raw_regexp = r"|".join("(%s)" % k for k in dct.keys())
self._substitutors = dct.values()
self._regexp = re.compile(self._raw_regexp, options)
def __repr__(self):
return "<%s at %d (%r)>" % (self.__class__.__name__, id(self),
self._raw_regexp)
def _subsitutor(self, *args, **kw):
def substitutor(match):
for substitutor, group in izip(self._substitutors, match.groups()):
if group is not None:
return substitutor(group, *args, **kw)
return substitutor
def __call__(self, string, *args, **kw):
return self._regexp.sub(self._subsitutor(*args, **kw), string)
def iwarn(iterable, message, category=None, stacklevel=1):
"""Make an iterator that run warnings.warn(message, category, stacklevel)
right before the first value from iterator is returned.
"""
warnings.warn(message, category, stacklevel)
for x in iterable:
yield x
# Stolen from Mako
class LRUCache(dict):
"""A dictionary-like object that stores a limited number of items, discarding
lesser used items periodically.
this is a rewrite of LRUCache from Myghty to use a periodic timestamp-based
paradigm so that synchronization is not really needed. the size management
is inexact.
"""
class _Item(object):
def __init__(self, key, value):
self.key = key
self.value = value
self.timestamp = time.time()
def __repr__(self):
return repr(self.value)
def __init__(self, capacity, threshold=.5):
self.capacity = capacity
self.threshold = threshold
def __getitem__(self, key):
item = dict.__getitem__(self, key)
item.timestamp = time.time()
return item.value
def values(self):
return [i.value for i in dict.values(self)]
def setdefault(self, key, value):
if key in self:
return self[key]
else:
self[key] = value
return value
def __setitem__(self, key, value):
item = dict.get(self, key)
if item is None:
item = self._Item(key, value)
dict.__setitem__(self, key, item)
else:
item.value = value
self._manage_size()
def _manage_size(self):
while len(self) > self.capacity + self.capacity * self.threshold:
bytime = dict.values(self)
bytime.sort(lambda a, b: cmp(b.timestamp, a.timestamp))
for item in bytime[self.capacity:]:
try:
del self[item.key]
except KeyError:
# if we couldnt find a key, most likely some other thread broke in
# on us. loop around and try again
break
def disable_runtime_checks():
"""
Disables runtime checks for possible programming errors regarding
modifying widget attributes once a widget has been initialized.
This option can significantly reduce Widget initialization time.
NOTE: This operation modifies the Widget class and will affect any
application using ToscaWidgets in the same process.
"""
from tw.api import Widget
del Widget.__setattr__
del Widget.__delattr__
if __name__ == "__main__":
import doctest
doctest.testmod()
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/middleware.py 0000644 0001750 0001750 00000011750 11175375027 023646 0 ustar zack zack from urllib import unquote
import pkg_resources
from webob import Request
import tw
from tw.mods import base
from tw.core import resources
from tw.core.util import asbool
__all__ = ["ToscaWidgetsMiddleware", "make_middleware"]
class ToscaWidgetsMiddleware(object):
"""
This WSGI middleware piece takes care of creating a per-request context for
ToscaWidgets and injecting resource links into html responses.
It can also take care of serving those resources if `serve_resources` is
True (default).
"""
def __init__(self, application, host_framework, prefix='/toscawidgets',
inject_resources=True, serve_resources=True):
self.host_framework = host_framework
self.prefix = prefix
self.serve_resources = serve_resources
self.inject_resources = inject_resources
self.application = application
if self.inject_resources:
from tw.core.resource_injector import injector_middleware
self.application = injector_middleware(self.application)
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
def wsgi_app(self, environ, start_response):
self.host_framework.start_request(environ)
environ['paste.registry'].register(tw.framework, self.host_framework)
#XXX Do we really need to stuff these in environ?
environ['toscawidgets.prefix'] = self.prefix
environ.setdefault('toscawidgets.framework', self.host_framework)
req = Request(environ)
try:
if self.serve_resources and req.path_info.startswith(self.prefix):
# Intercept request to possibly serve a static resource
req.path_info = req.path_info[len(self.prefix):]
req.script_name += self.prefix
resources_app = resources.registry
if req.path_info.startswith(resources_app.prefix):
req.path_info = req.path_info[len(resources_app.prefix):]
req.script_name += resources_app.prefix
resp = req.get_response(resources_app)
return resp(environ, start_response)
else:
# Pass request downstream
resp = req.get_response(self.application)
return resp(environ, start_response)
finally:
self.host_framework.end_request(environ)
#TODO: Wrap to issue deprecation warnings
TGWidgetsMiddleware = ToscaWidgetsMiddleware
def _load_from_entry_point(name):
for ep in pkg_resources.iter_entry_points('toscawidgets.host_frameworks'):
if ep.name == name:
return ep
def _extract_args(args, prefix, adapters={}):
l = len(prefix)
nop = lambda v: v
return dict((k[l:], adapters.get(k[l:], nop)(v))
for k,v in args.iteritems() if k.startswith(prefix))
def _load_host_framework(host_framework):
if ':' not in host_framework:
ep = _load_from_entry_point(host_framework)
else:
ep = pkg_resources.EntryPoint.parse("hf="+host_framework)
if ep:
hf = ep.load(False)
else:
hf = None
if not hf:
raise LookupError("Could not load %s" % host_framework)
return hf
def make_middleware(app, config=None, **kw):
"""
Initializes :class:`tw.core.middleware.ToscaWidgetsMiddleware` and a
:class:`tw.mods.base.HostFramework` and wraps the WSGI application ``app``
with it.
Configuration can be passed in a dict as the ``config`` parameter.
**Available options:**
toscawidgets.middleware.*
These parameters will be passed to
:class:`tw.core.middleware.ToscaWidgetsMiddleware`
when instatntiating it. See its docstrings for details.
toscawidgets.framework
Name of the ``toscawidgets.host_frameworks`` entry point or
:class:`tw.mods.base.HostFramework` subclass which shall interface with
the framework. ``wsgi``, ``pylons`` are available. Default is
``wsgi``
toscawidgets.framework.*
Parameters for the :class:`tw.modes.base.HostFramework`. See their
respective docstrings for accepted parameters.
This is the ToscaWidgets#middleware paste.filter_app_factory entrypoint.
"""
config = (config or {}).copy()
config.update(kw)
host_framework = config.pop('toscawidgets.framework', 'wsgi')
if isinstance(host_framework, basestring):
host_framework = _load_host_framework(host_framework)
middleware_args = _extract_args(config, 'toscawidgets.middleware.', {
'inject_resources': asbool,
'serve_resources': asbool,
})
hf_args = _extract_args(config, 'toscawidgets.framework.', {
'enable_runtime_checks': asbool,
})
app = ToscaWidgetsMiddleware(app, host_framework=host_framework(**hf_args),
**middleware_args)
if config.get('stack_registry', False):
from tw.core.registry import RegistryManager
app = RegistryManager(app)
return app
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/__init__.py 0000644 0001750 0001750 00000000360 11175375027 023263 0 ustar zack zack from exceptions import *
from meta import *
from util import *
from view import *
from base import *
from resources import *
from resource_injector import *
from js import *
from middleware import make_middleware
from tw.mods.base import *
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/engine_plugin.py 0000644 0001750 0001750 00000005035 11175375027 024353 0 ustar zack zack """
Default engine plugin for TGWidgets.
Based on BuffetString which is Copyright (c) 2006 Christian Wyglendowski
"""
import string
import os
from pkg_resources import resource_filename
class ToscaWidgetsTemplatePlugin(object):
# all template plugins need to define a default file extension
extension = ".html"
def __init__(self, extra_vars_func=None, config=None):
"""extra_vars_func == optional callable() that returns a dict
config == optional dict() of configuration settings
"""
self.get_extra_vars = extra_vars_func
if config:
self.config = config
else:
self.config = dict()
def load_template(self, template_name, template_string=None):
"""
template_name == dotted.path.to.template (without .ext)
template_string == string containing the template
The dotted notation is present because many template engines
allow templates to be compiled down to Python modules. TurboGears
uses that feature to its adavantage, and for ease of integration
the python.templating.engines plugin format requires the path to
the template to be supplied as a dotted.path.to.template regardless
of whether is is a module or not.
In the case of string.Template templates, they are just simple text
files, so we deal with the dotted notation and translate it into a
standard file path to open the text file.
"""
if template_string is not None:
return string.Template(template_string)
divider = template_name.rfind('.')
if divider >= 0:
package = template_name[:divider]
basename = template_name[divider + 1:] + self.extension
template_name = resource_filename(package, basename)
template_file = open(template_name)
template_obj = string.Template(template_file.read())
template_file.close()
return template_obj
def render(self, info, format="html", fragment=False, template=None):
"""
info == dict() of variables to stick into the template namespace
format == output format if applicable
fragment == special rules about rendering part of a page
template == compiled template as returned by `load_template`
"""
# check to see if we were passed a function get extra vars
if callable(self.get_extra_vars):
info.update(self.get_extra_vars())
return template.safe_substitute(**info)
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/resource_injector.py 0000644 0001750 0001750 00000011671 11175375027 025257 0 ustar zack zack """
.. testoutput::
:hide:
>>> # This is so the doctests start from a clean state
>>> from tw.core.util import install_framework; install_framework(True)
ToscaWidgets can inject resources that have been registered for injection in
the current request.
Usually widgets register them when they're displayed and they have instances of
:class:`tw.api.Resource` declared at their :attr:`tw.api.Widget.javascript` or
:attr:`tw.api.Widget.css` attributes.
Resources can also be registered manually from a controller or template by
calling their :meth:`tw.api.Resource.inject` method.
When a page including widgets is rendered, Resources that are registered for
injection arre collected in request-local
storage area (this means any thing stored here is only visible to one single
thread of execution and that its contents are freed when the request is
finished) where they can be rendered and injected in the resulting html.
ToscaWidgets' middleware can take care of injecting them automatically (default)
but they can also be injected explicitly, example::
>>> from tw.api import JSLink, inject_resources
>>> JSLink(link="http://example.com").inject()
>>> html = ""
>>> inject_resources(html)
''
Once resources have been injected they are popped from request local and
cannot be injected again (in the same request). This is useful in case
:class:`injector_middleware` is stacked so it doesn't inject them again.
Injecting them explicitly is neccesary if the response's body is being cached
before the middleware has a chance to inject them because when the cached
version is served no widgets are being rendered so they will not have a chance
to register their resources.
"""
import re
import logging
from webob import Request
from tw import framework
from tw.core.util import MultipleReplacer
log = logging.getLogger(__name__)
__all__ = ["inject_resources", "injector_middleware"]
def injector_middleware(app):
"""
Middleware that injects resources (if any) into the page whenever the
output is html (peeks into Content-Type header).
Normally you don't have to stack thi yourself because
:class:`tw.core.middleware.ToscaWidgetsMiddleware` does it when it is
passed the ``inject_resources`` flag as True (default).
"""
def _injector(environ, start_response):
req = Request(environ)
resp = req.get_response(app)
content_type = resp.headers.get('Content-Type','text/plain').lower()
if 'html' in content_type:
resources = framework.pop_resources()
if resources:
resp.body = inject_resources(resp.body, resources, resp.charset)
return resp(environ, start_response)
return _injector
class _ResourceInjector(MultipleReplacer):
def __init__(self):
return MultipleReplacer.__init__(self, {
r'': self._injector_for_location('head'),
r'': self._injector_for_location('headbottom', False),
r'': self._injector_for_location('bodytop'),
r'': self._injector_for_location('bodybottom', False)
}, re.I|re.M)
def _injector_for_location(self, key, after=True):
def inject(group, resources, encoding):
inj = u'\n'.join([r.render() for r in resources.get(key, [])])
inj = inj.encode(encoding)
if after:
return group + inj
return inj + group
return inject
def __call__(self, html, resources=None, encoding=None):
"""Injects resources, if any, into html string when called.
.. note::
Ignore the ``self`` parameter if seeing this as
:func:`tw.core.resource_injector.inject_resources` docstring
since it is an alias for an instance method of a private class.
``html`` must be a ``encoding`` encoded string. If ``encoding`` is not
given it will be tried to be derived from a .
Resources for current request can be obtained by calling
``tw.framework.pop_resources()``. This will remove resources
from request and a further call to ``pop_resources()`` will return an
empty dict.
"""
if resources is None:
resources = framework.pop_resources()
if resources:
# Only inject if there are resources registered for injection
encoding = encoding or find_charset(html) or 'ascii'
html = MultipleReplacer.__call__(self, html, resources, encoding)
return html
# Bind __call__ directly so docstring is included in docs
inject_resources = _ResourceInjector().__call__
_charset_re = re.compile(r"charset\s*=\s*(?P[\w-]+)([^\>])*",
re.I|re.M)
def find_charset(string):
m = _charset_re.search(string)
if m:
return m.group('charset').lower()
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/view.py 0000644 0001750 0001750 00000020232 11217766155 022501 0 ustar zack zack import sys
import logging
import re
import threading
from pkg_resources import iter_entry_points, load_entry_point
import tw
from tw.core.exceptions import WidgetException
from tw.core.util import LRUCache
__all__ = ["EngineManager", "Renderable", "EngineException", "display",
"render"]
log = logging.getLogger(__name__)
class EngineException(WidgetException):
pass
#XXX: This make_renderer/get_render_method/etc... is a mess which should be
# cleaned sometime
def make_renderer(method, doc=None):
def _renderer(self, renderable, **kw):
template = kw.pop('template', renderable.template)
if template is None:
return
origin = dynamic_best_engine(renderable, kw)
destination = kw.get('displays_on', renderable.displays_on)
if origin != 'cheetah':
template = self.load_template(template, origin)
renderer = self.get_render_method(origin, destination, method)
output = renderer(info=kw, template=template)
if method == 'display':
output = self.adapt_output(output, destination)
# Make sure string output is always unicode
if isinstance(output, str):
output = unicode(output, 'utf-8')
return output
_renderer.func_name = method
_renderer.__doc__ = doc
return _renderer
class EngineManager(dict):
"""
Manages availble templating engines.
"""
default_view = 'toscawidgets'
def __init__(self, extra_vars_func=None, options=None, load_all=False):
self.extra_vars_func = extra_vars_func
self.options = options
self._cache = LRUCache(50)
self._lock = threading.Lock()
if load_all:
self.load_all()
def __repr__(self):
return "< %s >" % self.__class__.__name__
def load_engine(self, name, options=None, extra_vars_func=None,
distribution=None):
factory = None
if distribution:
factory = load_entry_point(
distribution, "python.templating.engines", name)
else:
for entrypoint in iter_entry_points("python.templating.engines"):
if entrypoint.name == name:
factory = entrypoint.load()
if factory is None:
raise EngineException("No plugin available for engine '%s'" % name)
options = options or self.options or {}
options = options.copy()
# emulate Kid and Genshi's dotted-path notation lookup
options.setdefault('mako.directories', []).extend(sys.path)
# make sure mako produces utf-8 output so we can decode it and use
# unicode internally
options['mako.output_encoding'] = 'utf-8'
extra_vars_func = extra_vars_func or self.extra_vars_func
self._lock.acquire()
try:
self[name] = factory(extra_vars_func, options)
finally:
self._lock.release()
def __getitem__(self, name):
"""
Return a Buffet plugin by name. If the plugin is not loaded it
will try to load it with default arguments.
"""
try:
return dict.__getitem__(self, name)
except KeyError:
self.load_engine(name)
return dict.__getitem__(self, name)
def load_all(self, engine_options=None, stdvars=None, raise_error=False):
for ep in iter_entry_points("python.templating.engines"):
try:
self.load_engine(ep.name, engine_options, stdvars)
except:
log.warn("Failed to load '%s' template engine: %r",
ep.name, sys.exc_info())
if raise_error:
raise
def load_template(self, template, engine_name):
"""Return's a compiled template and it's enginename"""
output = None
if isinstance(template, basestring) and _is_inline_template(template):
# Assume inline template, try to fetch from cache
key = (template, engine_name)
try:
output = self._cache[key]
#log.debug("Cache hit for: %s", `key`)
except KeyError:
#log.debug("Cache miss for: %s", `key`)
output = self._cache[key] = self[engine_name].load_template(
None, template_string = template
)
elif isinstance(template, basestring):
# Assume template path
output = self[engine_name].load_template(template)
else:
# Assume compiled template
output = template
return output
display = make_renderer('display', doc=\
"""
Displays the renderable. Returns appropiate output for target template
engine
""")
render = make_renderer('render', doc=\
"""
Returns the serialized output in a string.
Useful for debugging or to return to the browser as-is.
""")
def get_render_method(self, origin, destination, method):
engine = self[origin]
# Only pass-through Element/Stream output if rendering on the same
# template engine as the one producing output
if method == 'display' and \
origin == destination and origin in ['kid', 'genshi']:
return engine.transform
# In any other case render as a string
def _render_xhtml(**kw):
kw.update(format='xhtml')
return engine.render(**kw)
return _render_xhtml
def adapt_output(self, output, destination):
# Handle rendering strings on Genshi so they're not escaped
if isinstance(output, basestring) and destination == 'genshi':
from genshi.input import HTML
output = HTML(output)
# Handle rendering strings on Kid so they're not escaped
elif isinstance(output, basestring) and destination == 'kid':
from kid import XML
output = XML(output)
return output
# Available as a public symbol for easier extension with PEAK-Rules for
# backwards compatibility
display = EngineManager.display.im_func
render = EngineManager.render.im_func
def choose_engine(obj, engine_name=None):
tpl = obj.template
if isinstance(tpl, basestring) and not _is_inline_template(tpl):
colon = tpl.find(":")
if colon > -1:
engine_name = tpl[:colon]
tpl = tpl[colon+1:]
return engine_name, tpl
def dynamic_best_engine(renderable, params):
try:
ideal_engine = params['displays_on']
except KeyError:
ideal_engine = renderable.displays_on
if ideal_engine not in renderable.available_engines:
try:
best_engine = params['engine_name']
except KeyError:
best_engine = renderable.engine_name
else:
best_engine = ideal_engine
assert best_engine is not None
return best_engine
_is_inline_template = re.compile(r'(<|\n|\$)').search
class Renderable(object):
"""Base class for all objects that the EngineManager can render"""
engine_name = 'toscawidgets'
available_engines = []
template = None
def displays_on(self):
return tw.framework.default_view
displays_on = property(displays_on, doc="""\
Where the Renderable is being displayed on
""")
def __new__(cls, *args, **kw):
obj = object.__new__(cls, *args, **kw)
obj.template = kw.pop("template", obj.template)
engine_name = kw.pop("engine_name", None)
if obj.template is not None:
colon_based_engine_name, obj.template = choose_engine(obj)
# if there is a colon in the engine name, the available engines should be narrowed
# to that engine.
if colon_based_engine_name:
obj.available_engines = [colon_based_engine_name,]
engine_name = colon_based_engine_name
if engine_name:
obj.engine_name = engine_name
return obj
def render(self, **kw):
kw.setdefault('_', tw.framework.translator)
return tw.framework.engines.render(self, **kw)
def display(self, **kw):
kw.setdefault('_', tw.framework.translator)
return tw.framework.engines.display(self, **kw)
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/exceptions.py 0000644 0001750 0001750 00000001447 11175375027 023714 0 ustar zack zack class WidgetException(RuntimeError):
msg = "Widget error"
def __init__(self, msg=None):
self.msg = msg or self.msg
def __str__(self):
return self.msg
class WidgetUnlocked(WidgetException, AttributeError):
msg = ("The widget is not locked. This method needs to wait until the "
"widget is fully locked in order to function properly")
class WidgetLocked(WidgetException, AttributeError):
msg = ("The widget is locked. It's unthread-safe to alter it's attributes "
"after initialization.")
class WidgetInitialized(WidgetException, AttributeError):
msg = ("The widget is already initialized, try doing it at the "
"constructor.")
class WidgetUninitialized(WidgetException, AttributeError):
msg = ("The widget is uninitialized.")
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/base.py 0000644 0001750 0001750 00000102452 11217751256 022442 0 ustar zack zack import re, weakref, logging
from copy import copy
from warnings import warn
from itertools import ifilter, count, chain, izip, islice, ifilterfalse
from inspect import isclass
import tw
from util import (assert_bool_attr, callable_wo_args,
unflatten_args, OrderedSet, make_bunch,
install_framework, ThreadSafeDescriptor,
RequestLocalDescriptor, LRUCache)
install_framework()
import view
from exceptions import *
from meta import WidgetType, WidgetsList
__all__ = [
"Widget",
"WidgetsList",
"WidgetRepeater",
"RepeatedWidget",
"WidgetBunch",
"RepeatingWidgetBunch",
"Child",
"valid_id",
"adapt_value",
]
log = logging.getLogger(__name__)
only_if_initialized = assert_bool_attr(
'_is_initialized', True, WidgetUninitialized
)
only_if_uninitialized = assert_bool_attr(
'_is_initialized', False, WidgetInitialized
)
def only_if_unlocked(func):
def __setattr__(self, k, *args):
descriptor = getattr(self.__class__, k, None)
if not isinstance(descriptor, ThreadSafeDescriptor) and self._is_locked:
raise WidgetLocked
func(self, k, *args)
return __setattr__
valid_id_re = re.compile(r'^[a-zA-Z][\w\-\_\:\.]*$')
_deprecated_id_re = re.compile(r'^\w+$')
def valid_id(s):
if valid_id_re.match(s):
return True
elif s == '_method':
#ignore this one small hack to help pages use HTTP verbs
return True
elif _deprecated_id_re.match(s):
warn("The id %s will no longer be supported since it doesn't conform "
"to the W3C Spec: http://www.w3.org/TR/xhtml1/#C_8" % s,
DeprecationWarning, 3)
return True
else:
return False
serial_generator = count()
class Widget(view.Renderable):
"""
Base class for all widgets.
Example:
.. sourcecode:: python
>>> w = Widget('foo')
>>> w.id
'foo'
>>> w = Widget('foo', children=[Widget('c1'), Widget('c2')])
>>> [c.id for c in w.children]
['foo_c1', 'foo_c2']
>>> [c.parent.id for c in w.children]
['foo', 'foo']
It is a **must** that all initial state is entirely determined by the
arguments to this function. This means that two widgets
(of the same class) that receive the same parameters
must behave in exactly the same way. You should not rely on external
sources inside __init__ to set initial state.
If you need to fetch data from external sources, do it at
:meth:`update_params` instead.
Essential pre, and post initialization is done in :meth:`__new__` and
:meth:`post_init` respectively. :meth:`post_init` is guaranteed to run after
the instance finishes initialization and it's behavior is rather special
as all post_init's in mro will be called to have a chance to set final
state in the instance.
Basic pre-initialization consists of binding all kw arguments to the
widget instance, attaching the widget to it's parent (if given),
attaching the children and copying mutable arguments listed at
:attr:`params` from the class to the instance to avoid accidental
manipulation.
.. sourcecode:: python
>>> w = Widget('foo', a=1, b=2)
>>> w.id
'foo'
>>> w.a
1
>>> w.b
2
Basic post-initialization consists of caching required CSS and JS
resources and setting the widget as initialized preventing further
modification of it's attributes.
.. sourcecode:: python
>>> w = Widget('foo', a='1', b='2')
>>> w.a = 'bar'
Traceback (most recent call last):
...
WidgetLocked: The widget is locked. It's unthread-safe to alter it's attributes after initialization.
Widget attributes can only be modified in this method because widgets
should behave in a state-less way as they are shared among threads for
multiple requests.
Per request modification of variables sent to the template should be
done inside :meth:`update_params` and all state flowing from parent to
children should occur inside that dict.
Widgets should be instantiated at import time and reused among requests,
most widgets allow overriding most of their parameters (not neccesarily all
of them) at display time to change behavior. You should try avoiding
instantiating widgets for every request as their initialization could be
quite expensive for heavily nested widgets.
Request-local storage provided by the hosting framework in
``tw.framework.request`` can be used to pass state among widgets
which don't share the same root.
"""
__metaclass__ = WidgetType
parent = None
default = None
params = {
'id': ('The id of this widget. This id is used to reference a widget '
'from its parent ``children`` attribute and is usually the '
'DOM id of outermost HTML tag of the widget.'),
'css_class': 'Main CSS class for this widget',
'css_classes': 'A list with extra css classes for the widget.'
}
css = []
javascript = []
css_classes = []
_is_initialized = False
_is_locked = False
def displays_on(self):
if self.is_root:
return tw.framework.default_view
else:
return self.parent.engine_name
displays_on = property(displays_on, doc="""\
Where the widget is being displayed on
""")
#XXX: Some of these properties could be implemented as static attributes
def id(self):
return '_'.join(reversed(
[w.id_path_elem for w in self.path if w.id_path_elem]
)) or None
id = property(id, doc="""\
The calculated id of the widget. This string will provide a unique
id for each widget in the tree in a format which allows to re-recreate
the nested structure.
Example::
>>> A = Widget("A", children=[
... Widget("B", children=[
... Widget("C")
... ])
... ])
...
>>> C = A.c.B.c.C
>>> C.id
'A_B_C'
""")
def key(self):
return '.' + '.'.join(reversed(
[w.id_path_elem for w in self.path if w.id_path_elem][:-1]
)) or None
key = property(key, doc="""\
A string that can be used as a key to index the dictionary of
parameters sent to the root widget so it reaches this widget when
displaying.
Example::
>>> A = Widget("A", children=[
... Widget("B", children=[
... Widget("C")
... ])
... ])
...
>>> C = A.c.B.c.C
>>> C.key
'.B.C'
""")
def path(self):
item = self
while item:
yield item
item = item.parent
path = property(path, doc="""\
Iterates a walk from this widget to the root of the tree
""")
@property
def id_path_elem(self):
return self._id
def root(self):
return list(self.path)[-1]
root = property(root, doc="The root of this widget tree")
def is_root(self):
return self.parent is None
is_root = property(is_root, doc="True if the widget doesn't have a parent")
def __new__(cls, id=None, parent=None, children=[], **kw):
"""
Takes care of Widget instances creation. Should not need to be overrien
likely.
"""
obj = view.Renderable.__new__(cls,id,parent,children,**kw)
# The previous version of this used the __dict__ attribute to update
# things, but that doesn't fire any fset properties, and can actually
# lose data if a property is set, the following will not behave like
# that
for k,v in kw.iteritems():
if not k.startswith('_'):
try:
setattr(obj, k, v)
except AttributeError, e:
#skip setting the value of a read only property
pass
obj.orig_kw = kw.copy()
if id is not None and not valid_id(id):
raise ValueError("%r is not a valid id for a Widget"%id)
obj._id = id
obj._serial = serial_generator.next()
# Attach the widget to its parent
if parent is not None:
if parent._is_initialized:
raise WidgetInitialized
obj.parent = weakref.proxy(parent)
obj.parent.children.append(obj)
# Append children passed as args or defined in the class, former
# override later
obj.c = obj.children = WidgetBunch()
if isclass(children) and issubclass(children, WidgetsList):
children = children()
if not [obj._append_child(c) for c in children]:
cls_children = cls._cls_children
if isclass(cls_children) and issubclass(cls_children, WidgetsList):
cls_children = cls_children()
[obj._append_child(c) for c in cls_children]
# Copy mutable attrs from __class__ into self, if not found in self
# set to None
for name in chain(cls.params, ['css', 'javascript']):
try:
attr = getattr(obj, name, None)
if isinstance(attr, (list,dict)):
attr = copy(attr)
setattr(obj, name, attr)
except AttributeError:
# In case we try to set a read-only property
pass
# Initialize the static js calls list
obj._js_calls = []
# Initialize resources OrderedSet
obj._resources = OrderedSet()
# Set default css class for the widget
if not getattr(obj, 'css_class', None):
obj.css_class = obj.__class__.__name__.lower()
return obj
@only_if_initialized
def clone(self, *args, **kw):
"""
Returns a cloned version of the widget instance, optionally
overriding initialization parameters.
This is the only way to safely "modify" a widget instance.
Example::
>>> w = Widget('foo', a=2)
>>> w.id, w.a
('foo', 2)
>>> w2 = w.clone(a=3)
>>> w2.id, w2.a
('foo', 3)
"""
#log.debug("Cloning %r", self)
return Child(
self.__class__, self._id, children=self.children, **self.orig_kw
)(*args, **kw)
@only_if_initialized
def _as_repeated(self, *args, **kw):
cls = self.__class__
new_name = 'Repeated'+cls.__name__
new_class = type(new_name, (RepeatedWidget, cls), {})
#log.debug("Generating %r for repeating %r", new_class, self)
return Child(
new_class, self._id, children=self.children, **self.orig_kw
)(*args, **kw)
def __init__(self, id=None, parent=None, children=[], **kw):
"""Initializes a Widget instance.
`id`
The widget's id. All widgets in the same level of nested
widgets trees should have distinct ids.
`parent`
A reference to the widget's parent. This parent needs to be in an
uninitialized state which means it can only be passed to a child
inside the parent's __init__ method.
`children`
A list, or WidgetsList (instance or class) or any other iterable
with a reference to the children this widget should have.
`\*\*kw`
Any other extra keyword arguments for the widget. All of these will
get bound to the Widget instance.
"""
# we need a dummy init here for the metaclass to wrap
pass
def _collect_resources(self):
"""picks up resources from self and all children"""
oset = self._resources
oset.add_all(chain(*[c._resources for c in self.css]))
oset.add_all(chain(*[c._resources for c in self.javascript]))
oset.add_all(chain(*[c._resources for c in self.children]))
def post_init(self, *args, **kw):
"""
This method is called for all :class:`tw.api.Widget` base classes to
perform final setup after the widget is initialized but before it is
locked.
"""
if len(self._js_calls) > 0:
from tw.core.resources import JSFunctionCalls
#log.debug("Creating JSFunctionCalls for %r. Functions: %s",
#self, self._js_calls,
#)
self.javascript.append(
JSFunctionCalls(function_calls=self._js_calls)
)
self._collect_resources()
#log.debug("Finished initializing %r", self)
assert not self._is_initialized
self._is_initialized = True
assert not self._is_locked
self._is_locked = True
def walk(self, filter=None, recur_if_filtered=True):
"""
Does a pre-order walk on widget tree rooted at self optionally
applying a filter on them.
Example::
>>> W = Widget
>>> w = W('a', children=[W('b', children=[W('c')]), W('d')])
>>> ''.join(i._id for i in w.walk())
'abcd'
>>> ''.join(i._id for i in w.walk(lambda x: not x.is_root))
'bcd'
>>> ''.join(i._id for i in w.walk(lambda x: x._id == 'c'))
'c'
Recursion can be prevented on children that not match filter.
>>> ''.join(i._id for i in w.walk(lambda x: x._id == 'c', False))
''
"""
def _walk():
yield self
iterator = iter(self.children)
if filter and not recur_if_filtered:
iterator = self.ifilter_children(filter)
for c in iterator:
for w in c.walk(filter, recur_if_filtered):
yield w
if filter:
return ifilter(filter, _walk())
return _walk()
def add_call(self, call, location="bodybottom"):
"""
Adds a :func:`tw.api.js_function` call that will be made when the
widget is rendered.
"""
if self._is_initialized:
#log.debug("Adding call <%s> for %r dynamically.", call, self)
from tw.core.resources import dynamic_js_calls
dynamic_js_calls.inject_call(call, location)
else:
#log.debug("Adding call <%s> for %r statically.", call, self)
self._js_calls.append(str(call))
@only_if_initialized
def retrieve_css(self):
warn("retrieve_css is deprecated. Please use retrieve_resources "
"instead and filter them yourself", DeprecationWarning, 2)
return []
@only_if_initialized
def retrieve_javascript(self):
warn("retrieve_javascript is deprecated. Please use retrieve_resources "
"instead and filter them yourself", DeprecationWarning, 2)
return []
@only_if_initialized
def retrieve_resources(self):
"""
Returns a dict keyed by location with ordered collections of
resources from this widget and its children as values.
"""
from tw.api import locations
resources = dict((k, OrderedSet()) for k in locations)
for r in self._resources:
resources[r.location].add(r)
return resources
def adapt_value(self, value):
"""
Adapt object *value* for rendering in this widget. Should return one of:
* A list of objects for repeated widgets.
* A dict for widgets with children, keyed by the children's ids.
* Any other object the widget understands.
"""
# Handle MultiDict instances
if hasattr(value, 'dict_of_lists'):
for k, v in value.dict_of_lists().items():
if len(v) == 1:
value[k] = v[0]
else:
value[k] = v
# If we have children, create a dict from the attributes of value
elif len(self.children_deep) > 0 and not isinstance(value, (dict,list)):
value = dict([
(w._id, getattr(value, w._id))
for w in self.children_deep if w._id and hasattr(value, w._id)
])
return value
def register_resources(self):
"""
Register the resources required by this Widget with
:attr:`tw.framework` for inclusion in the page.
This method is called whenever a :class:`Widget` is rendered
"""
if self.is_root:
tw.framework.register_resources(self.retrieve_resources())
def render(self, value=None, **kw):
"""
Renders a widget as an unicode string.
"""
kw = self.prepare_dict(value, kw)
self.register_resources()
return super(Widget, self).render(**kw)
def display(self, value=None, **kw):
"""
Renders a widget and adapts the output. This method **must** be used
to display child widgets inside their parent's template so output is
adapted.
Unlike :meth:`tw.api.Widget.render`, :meth:`tw.api.Widget.display`
returns adapted output compatible with the template the widget is being
rendered on. For example, this is needed so Genshi doesn't autoescape
string output from mako and to serialize Genshi output on the other way
around.
"""
kw = self.prepare_dict(value, kw)
self.register_resources()
return super(Widget, self).display(**kw)
def __call__(self, value=None, **kw):
return self.display(value, **kw)
def get_default(self):
"""Returns the default value for the widget. If the default is a funtion
that it can be called without arguments it will be called on each
render to retrieve a value"""
if callable_wo_args(self.default):
value = self.default()
else:
value = self.default
return value
@property
def children_deep(self):
return self.children
def prepare_dict(self, value, d, adapt=True):
"""
Prepares the all kw arguments sent to `display` or `render` before
passing the kw argument's dict to `update_params`.
"""
if value is None:
value = self.get_default()
if adapt:
d['value'] = self.adapt_value(value)
else:
d['value'] = value
# Move args passed to child widgets into child_args
child_args = d.setdefault('child_args', {})
for k in d.keys():
if '.' in k:# or '-' in k:
child_args[k.lstrip('.')] = d.pop(k)
d['args_for'] = self._get_child_args_getter(child_args)
d['value_for'] = self._get_child_value_getter(d['value'])
d['c'] = d['children'] = self.children
d = make_bunch(d)
self.update_params(d)
s = set([d['css_class'],])
classes = d['css_classes']
for item in classes:
s.add(item)
# Compute the final css_class string
d['css_class']= ' '.join(s)
# reset the getters here so update_params has a chance to alter
# the arguments to children and the value
d['args_for'] = self._get_child_args_getter(d['child_args'])
d['value_for'] = self._get_child_value_getter(d.get('value'))
# Provide a shortcut to display a child field in the template
d['display_child'] = self._child_displayer(self.children,
d['value_for'],
d['args_for'])
return d
def update_params(self, d):
"""
Updates the dict sent to the template for the current request.
It is called when displaying or rendering a widget with all keyword
arguments passed stuffed inside dict.
Widget subclasses can call super cooperatively to avoid
boiler-plate code as `Widget.update_params` takes care of pre-populating
this dict with all attributes from self listed at `params`
(copying them if mutable) and preparing arguments for child widgets.
Any parameter sent to `display` or `render` will override those fetched
from the instance or the class.
Any function listed at `params` which can be called without arguments
will be automatically called to fetch fresh results on every request.
Parameters not found either on the class, the instance or the keyword
args to `display` or `render` will be set to None.
.. sourcecode:: python
>>> class MyWidget(Widget):
... params = ["foo", "bar", "null"]
... foo = "foo"
...
>>> w = MyWidget('test', bar=lambda: "bar")
>>> d = {}
>>> w.update_params(d)
>>> d['bar']
'bar'
>>> d['foo']
'foo'
>>> d['null'] is None
True
>>> d = {'foo':'overriden'}
>>> w.update_params(d)
>>> d['foo']
'overriden'
"""
# Populate dict with attrs from self listed at params
for k in ifilterfalse(d.__contains__, self.params):
attr = getattr(self, k, None)
if attr is not None:
if isinstance(attr, (list, dict)):
attr = copy(attr)
# Variables that are callable with no args are automatically
# called here
elif not isinstance(attr, Widget) and callable_wo_args(attr):
log.debug("Autocalling param '%s'", k)
attr = attr()
d[k] = attr
def ifilter_children(self, filter):
"""
Returns an iterator for all children applying a filter to them.
.. sourcecode:: python
>>> class Widgets(WidgetsList):
... aa = Widget()
... ab = Widget()
... ba = Widget()
... bb = Widget()
...
>>> w = Widget(children=Widgets)
>>> [c.id for c in w.ifilter_children(lambda w: w.id.startswith('a'))]
['aa', 'ab']
"""
return ifilter(filter, self.children)
def _get_child_value_getter(self, value):
def value_getter(child_id):
if value:
if (hasattr(child_id, 'repetition') and
isinstance(value,list)
):
child_id = child_id.repetition
elif isinstance(child_id, Widget) and isinstance(value,dict):
child_id = child_id._id
try:
return value[child_id]
except (IndexError,KeyError,TypeError):
None
return value_getter
def _get_child_args_getter(self, child_args):
if isinstance(child_args, dict):
child_args = unflatten_args(child_args)
def args_getter(child_id):
if (hasattr(child_id, 'repetition') and
isinstance(child_args, list)
):
child_id = child_id.repetition
elif (isinstance(child_id, Widget) and
isinstance(child_args, dict)
):
child_id = child_id._id
try:
return child_args[child_id]
except (IndexError,KeyError,TypeError):
return {}
return args_getter
@only_if_uninitialized
def _append_child(self,obj):
"""Append an object as a child"""
if isinstance(obj, Widget):
obj._append_to(self)
elif isinstance(obj, Child):
obj(self)
else:
raise ValueError("Can only append Widgets or Childs, not %r" % obj)
@only_if_initialized
def _append_to(self, parent=None):
return self.clone(parent)
@only_if_unlocked
def __setattr__(self,k,v):
object.__setattr__(self,k,v)
@only_if_unlocked
def __delattr__(self,k):
object.__delattr__(self,k)
def __repr__(self):
name = self.__class__.__name__
return "%s(%r, children=%r, **%r)" % (
name, self._id, self.children, self.orig_kw
)
def __str__(self):
return self.render()
def __ne__(self, other):
return not (self == other)
def __eq__(self, other):
return (
(getattr(other, '__class__', None) is self.__class__) and
# Check _id so ancestors are not taken into account
(other._id == self._id) and
(other.children == self.children) and (other.orig_kw == self.orig_kw)
)
@staticmethod
def _child_displayer(children, value_for, args_for):
def display_child(widget, **kw):
if isinstance(widget, (basestring,int)):
widget = children[widget]
child_kw = args_for(widget)
child_kw.update(kw)
return widget.display(value_for(widget), **child_kw)
return display_child
# Available as a public symbol for easier extension with PEAK-Rules for
# backwards compatibility
adapt_value = Widget.adapt_value.im_func
class Child(object):
"""
Prepares a Widget to being attached to a parent Widget.
Creates a Widget instance with supplied arguments to the constructor when
called (optionally overriding default arguments).
>>> c = Child(Widget, 'foo')
>>> w = c()
>>> w.id
'foo'
Parameters can be overriden when called.
>>> w = c(id='bar')
>>> w.id
'bar'
"""
__slots__ = ("widget_class", "id", "children", "kw")
def __init__(self, widget_class, id=None, children=[], **kw):
self.widget_class, self.id = widget_class, id,
self.children, self.kw = children, kw
def __call__(self, parent=None, **kw):
kw_ = self.kw.copy()
kw_.update(id=self.id, parent=parent, children=self.children)
kw_.update(kw)
return self.widget_class(**kw_)
#XXX: Should enhance and clean up so setting widgets is not allowed if the
# WidgetBunch is used as a widget's 'children' attribute and the widget
# is already initialized. BTW, this WidgetBunch_attrs thingie is becomming
# ugly ... should re-implement properly someday...
_WidgetBunch_attrs = frozenset(['_widget_lst', '_widget_dct', '_widget',
'_repetitions', '_parent', '_repetition_cache'])
class WidgetBunch(object):
"""
An ordered collection of widgets.
>>> from tw.core import Widget
>>> wb = WidgetBunch(Widget('foo'), Widget('bar'))
>>> wb[0].id == 'foo'
True
>>> wb[1].id == 'bar'
True
Exposes a mixed dict/list interface which permits indexing both by widget
id and position.
>>> wb['foo'] == wb[0]
True
>>> wb['bar'] == wb[1]
True
Also permits attribute access as long as the attribute doesn't conflict
with an internal attribute, in case of conflict the internal attrbute
will prevail.
>>> wb.foo.id == 'foo'
True
>>> wb.append(Widget('append'))
>>> wb.append.id
Traceback (most recent call last):
...
AttributeError: 'function' object has no attribute 'id'
>>> wb['append'].id == 'append'
True
Iteration is also supported
>>> [w.id for w in wb]
['foo', 'bar', 'append']
Some dict-like iterators too
>>> [id for id in wb.iterkeys()]
['foo', 'bar', 'append']
>>> [id for id in wb.keys()]
['foo', 'bar', 'append']
>>> [w.id for w in wb.itervalues()]
['foo', 'bar', 'append']
>>> [w.id for w in wb.values()]
['foo', 'bar', 'append']
"""
def __init__(self, *args):
self._widget_lst = []
self._widget_dct = {}
for wid in args:
self.append(wid)
def append(self,wid):
self.__setattr__(wid._id, wid)
def retrieve_css(self):
oset = OrderedSet()
for child in self:
oset.add_all(child.retrieve_css())
return oset
def retrieve_javascript(self):
oset = OrderedSet()
for child in self:
oset.add_all(child.retrieve_javascript())
return oset
def retrieve_resources(self):
from tw.core.resources import merge_resources, locations
resources = dict((k, OrderedSet()) for k in locations)
for w in self:
merge_resources(resources, w.retrieve_resources())
return resources
def __getitem__(self, item):
if isinstance(item, basestring):
return self._widget_dct[item]
elif isinstance(item, int):
return self._widget_lst[item]
raise KeyError, "No widget by %r" % item
def __getattr__(self, name):
if name in _WidgetBunch_attrs:
return object.__getattribute__(self,name)
try:
return self[name]
except KeyError:
raise AttributeError, "No widget by %r" % name
def __setattr__(self, name, value):
# Note that this setattr allows name = None so append can use it.
if name in _WidgetBunch_attrs:
return object.__setattr__(self,name,value)
self._widget_lst.append(value)
self._widget_dct[name] = value
def __iter__(self):
for wid in self._widget_lst:
yield wid
def __ne__(self, other):
return not (self==other)
def __eq__(self, other):
try:
if len(self) == len(other):
for a,b in izip(other,self):
if a!=b: return False
return True
except TypeError: pass
return False
def __getslice__(self,start=0,stop=-1,step=1):
return islice(self,start,stop,step)
def __len__(self):
return len(self._widget_lst)
def __nonzero__(self):
return bool(len(self))
def __contains__(self,item):
dct = self._widget_dct
try:
return dct[item._id] == item
except KeyError:
return False
def keys(self):
return list(self.iterkeys())
def iterkeys(self):
for w in self: yield w._id
def values(self):
return list(self.itervalues())
itervalues = __iter__
def __repr__(self):
return `self._widget_lst`
class RepeatingWidgetBunch(WidgetBunch):
_repetitions = 0
_widget = None
def __init__(self, *args, **kw):
super(RepeatingWidgetBunch, self).__init__(*args, **kw)
self._repetition_cache = LRUCache(100)
def __len__(self):
return self._repetitions
def __iter__(self, reps=None):
if reps is None:
reps = self._repetitions
for i in xrange(reps):
yield self[i]
def __getitem__(self, item):
if not isinstance(item, int):
raise KeyError("Must specify an integer")
try:
rep = self._repetition_cache[item]
except KeyError:
rep = self._widget.clone(repetition=item)
# Work around widget's locking mechanism since it is thread-safe
# to do it *here*. Note that the parent is not directly aware that
# it has this repeated widget as a child and it doesn't care
# really since I create those children on the fly
object.__setattr__(rep, 'parent', self._parent)
self._repetition_cache[item] = rep
return rep
class WidgetRepeater(Widget):
params = ["repetitions", "extra"]
widget = None
repetitions = 3
max_repetitions = None
extra = 0
id_path_elem = None
template = "$output"
@property
def key(self):
raise AttributeError("A WidgetRepeater has no meaningful key")
def __new__(cls, id=None, parent=None, children=[], **kw):
widget = kw.get('widget', getattr(cls, 'widget', None))
if widget is None:
warn("No repeated widget specified in %s" % cls.__name__)
widget = Widget()
if isclass(widget) and issubclass(widget, Widget):
widget = widget()
obj = super(WidgetRepeater, cls).__new__(cls, id,parent,**kw)
obj.c = obj.children = RepeatingWidgetBunch()
obj.c._parent = weakref.proxy(obj)
obj.c._repetitions = kw.get('repetitions', cls.repetitions)
obj.c._widget = widget._as_repeated(obj, id=obj._id)
return obj
def update_params(self, d):
super(WidgetRepeater,self).update_params(d)
if d.get('max_repetitions', self.max_repetitions) is not None:
warn("max_repetitions is deperecated and no longer has any effect",
DeprecationWarning, 3)
v_f = d['value_for']
a_f = d['args_for']
outputs = [
w.render(v_f(w), isextra=(w.repetition >= len(d['value'])), **a_f(w)) for w in d['children'].__iter__(
max(d['repetitions'], len(d['value']) + d.extra))
]
d["output"] = '\n'.join(o for o in outputs if o)
class RepeatedWidget(Widget):
params = ["repetition"]
repetition = 0
@property
def id_path_elem(self):
return '%s-%d' % (self._id, self.repetition or 0)
@only_if_initialized
def _as_repeated(self, *args, **kw):
return self.clone(*args, **kw)
if __name__ == "__main__":
import doctest
doctest.testmod(optionflags = doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE)
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/core/registry.py 0000644 0001750 0001750 00000055450 11175375027 023406 0 ustar zack zack # (c) 2005 Ben Bangert
# This module is part of the Python Paste Project and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
"""Registry for handling request-local module globals sanely
Dealing with module globals in a thread-safe way is good if your
application is the sole responder in a thread, however that approach fails
to properly account for various scenarios that occur with WSGI applications
and middleware.
What is actually needed in the case where a module global is desired that
is always set properly depending on the current request, is a stacked
thread-local object. Such an object is popped or pushed during the request
cycle so that it properly represents the object that should be active for
the current request.
To make it easy to deal with such variables, this module provides a special
StackedObjectProxy class which you can instantiate and attach to your
module where you'd like others to access it. The object you'd like this to
actually "be" during the request is then registered with the
RegistryManager middleware, which ensures that for the scope of the current
WSGI application everything will work properly.
Example:
.. code-block:: python
#yourpackage/__init__.py
from tw.core.registry import RegistryManager, StackedObjectProxy
myglobal = StackedObjectProxy()
#wsgi app stack
app = RegistryManager(yourapp)
#inside your wsgi app
class yourapp(object):
def __call__(self, environ, start_response):
obj = someobject # The request-local object you want to access
# via yourpackage.myglobal
if environ.has_key('paste.registry'):
environ['paste.registry'].register(myglobal, obj)
You will then be able to import yourpackage anywhere in your WSGI app or in
the calling stack below it and be assured that it is using the object you
registered with Registry.
RegistryManager can be in the WSGI stack multiple times, each time it
appears it registers a new request context.
Performance
===========
The overhead of the proxy object is very minimal, however if you are using
proxy objects extensively (Thousands of accesses per request or more), there
are some ways to avoid them. A proxy object runs approximately 3-20x slower
than direct access to the object, this is rarely your performance bottleneck
when developing web applications.
Should you be developing a system which may be accessing the proxy object
thousands of times per request, the performance of the proxy will start to
become more noticeable. In that circumstance, the problem can be avoided by
getting at the actual object via the proxy with the ``_current_obj`` function:
.. code-block:: python
#sessions.py
Session = StackedObjectProxy()
# ... initialization code, etc.
# somemodule.py
import sessions
def somefunc():
session = sessions.Session._current_obj()
# ... tons of session access
This way the proxy is used only once to retrieve the object for the current
context and the overhead is minimized while still making it easy to access
the underlying object. The ``_current_obj`` function is preceded by an
underscore to more likely avoid clashing with the contained object's
attributes.
**NOTE:** This is *highly* unlikely to be an issue in the vast majority of
cases, and requires incredibly large amounts of proxy object access before
one should consider the proxy object to be causing slow-downs. This section
is provided solely in the extremely rare case that it is an issue so that a
quick way to work around it is documented.
"""
import sys
import threading as threadinglocal
__all__ = ['StackedObjectProxy', 'RegistryManager', 'StackedObjectRestorer',
'restorer', 'Registry']
try:
from paste.registry import StackedObjectProxy, RegistryManager, StackedObjectRestorer, restorer, Registry
except ImportError:
class NoDefault(object): pass
class StackedObjectProxy(object):
"""Track an object instance internally using a stack
The StackedObjectProxy proxies access to an object internally using a
stacked thread-local. This makes it safe for complex WSGI environments
where access to the object may be desired in multiple places without
having to pass the actual object around.
New objects are added to the top of the stack with _push_object while
objects can be removed with _pop_object.
"""
def __init__(self, default=NoDefault, name="Default"):
"""Create a new StackedObjectProxy
If a default is given, its used in every thread if no other object
has been pushed on.
"""
self.__dict__['____name__'] = name
self.__dict__['____local__'] = threadinglocal.local()
if default is not NoDefault:
self.__dict__['____default_object__'] = default
def __dir__(self):
"""Return a list of the StackedObjectProxy's and proxied
object's (if one exists) names.
"""
dir_list = dir(self.__class__) + self.__dict__.keys()
try:
dir_list.extend(dir(self._current_obj()))
except TypeError:
pass
dir_list.sort()
return dir_list
def __getattr__(self, attr):
return getattr(self._current_obj(), attr)
def __setattr__(self, attr, value):
setattr(self._current_obj(), attr, value)
def __delattr__(self, name):
delattr(self._current_obj(), name)
def __getitem__(self, key):
return self._current_obj()[key]
def __setitem__(self, key, value):
self._current_obj()[key] = value
def __delitem__(self, key):
del self._current_obj()[key]
def __call__(self, *args, **kw):
return self._current_obj()(*args, **kw)
def __repr__(self):
try:
return repr(self._current_obj())
except (TypeError, AttributeError):
return '<%s.%s object at 0x%x>' % (self.__class__.__module__,
self.__class__.__name__,
id(self))
def __iter__(self):
return iter(self._current_obj())
def __len__(self):
return len(self._current_obj())
def __contains__(self, key):
return key in self._current_obj()
def __nonzero__(self):
return bool(self._current_obj())
def _current_obj(self):
"""Returns the current active object being proxied to
In the event that no object was pushed, the default object if
provided will be used. Otherwise, a TypeError will be raised.
"""
objects = getattr(self.____local__, 'objects', None)
if objects:
return objects[-1]
else:
obj = self.__dict__.get('____default_object__', NoDefault)
if obj is not NoDefault:
return obj
else:
raise TypeError(
'No object (name: %s) has been registered for this '
'thread' % self.____name__)
def _push_object(self, obj):
"""Make ``obj`` the active object for this thread-local.
This should be used like:
.. code-block:: python
obj = yourobject()
module.glob = StackedObjectProxy()
module.glob._push_object(obj)
try:
... do stuff ...
finally:
module.glob._pop_object(conf)
"""
if not hasattr(self.____local__, 'objects'):
self.____local__.objects = []
self.____local__.objects.append(obj)
def _pop_object(self, obj=None):
"""Remove a thread-local object.
If ``obj`` is given, it is checked against the popped object and an
error is emitted if they don't match.
"""
if not hasattr(self.____local__, 'objects'):
raise AssertionError('No object has been registered for this thread')
popped = self.____local__.objects.pop()
if obj:
if popped is not obj:
raise AssertionError(
'The object popped (%s) is not the same as the object '
'expected (%s)' % (popped, obj))
def _object_stack(self):
"""Returns all of the objects stacked in this container
(Might return [] if there are none)
"""
try:
return self.____local__.objects[:]
except AssertionError:
return []
# The following methods will be swapped for their original versions by
# StackedObjectRestorer when restoration is enabled. The original
# functions (e.g. _current_obj) will be available at _current_obj_orig
def _current_obj_restoration(self):
request_id = restorer.in_restoration()
if request_id:
return restorer.get_saved_proxied_obj(self, request_id)
return self._current_obj_orig()
_current_obj_restoration.__doc__ = \
('%s\n(StackedObjectRestorer restoration enabled)' % \
_current_obj.__doc__)
def _push_object_restoration(self, obj):
if not restorer.in_restoration():
self._push_object_orig(obj)
_push_object_restoration.__doc__ = \
('%s\n(StackedObjectRestorer restoration enabled)' % \
_push_object.__doc__)
def _pop_object_restoration(self, obj=None):
if not restorer.in_restoration():
self._pop_object_orig(obj)
_pop_object_restoration.__doc__ = \
('%s\n(StackedObjectRestorer restoration enabled)' % \
_pop_object.__doc__)
class Registry(object):
"""Track objects and stacked object proxies for removal
The Registry object is instantiated a single time for the request no
matter how many times the RegistryManager is used in a WSGI stack. Each
RegistryManager must call ``prepare`` before continuing the call to
start a new context for object registering.
Each context is tracked with a dict inside a list. The last list
element is the currently executing context. Each context dict is keyed
by the id of the StackedObjectProxy instance being proxied, the value
is a tuple of the StackedObjectProxy instance and the object being
tracked.
"""
def __init__(self):
"""Create a new Registry object
``prepare`` must still be called before this Registry object can be
used to register objects.
"""
self.reglist = []
def prepare(self):
"""Used to create a new registry context
Anytime a new RegistryManager is called, ``prepare`` needs to be
called on the existing Registry object. This sets up a new context
for registering objects.
"""
self.reglist.append({})
def register(self, stacked, obj):
"""Register an object with a StackedObjectProxy"""
myreglist = self.reglist[-1]
stacked_id = id(stacked)
if stacked_id in myreglist:
stacked._pop_object(myreglist[stacked_id][1])
del myreglist[stacked_id]
stacked._push_object(obj)
myreglist[stacked_id] = (stacked, obj)
# Replace now does the same thing as register
replace = register
def cleanup(self):
"""Remove all objects from all StackedObjectProxy instances that
were tracked at this Registry context"""
for stacked, obj in self.reglist[-1].itervalues():
stacked._pop_object(obj)
self.reglist.pop()
class RegistryManager(object):
"""Creates and maintains a Registry context
RegistryManager creates a new registry context for the registration of
StackedObjectProxy instances. Multiple RegistryManager's can be in a
WSGI stack and will manage the context so that the StackedObjectProxies
always proxy to the proper object.
The object being registered can be any object sub-class, list, or dict.
Registering objects is done inside a WSGI application under the
RegistryManager instance, using the ``environ['paste.registry']``
object which is a Registry instance.
"""
def __init__(self, application, streaming=False):
self.application = application
self.streaming = streaming
def __call__(self, environ, start_response):
app_iter = None
reg = environ.setdefault('paste.registry', Registry())
reg.prepare()
if self.streaming:
return self.streaming_iter(reg, environ, start_response)
try:
app_iter = self.application(environ, start_response)
except Exception, e:
# Regardless of if the content is an iterable, generator, list
# or tuple, we clean-up right now. If its an iterable/generator
# care should be used to ensure the generator has its own ref
# to the actual object
if environ.get('paste.evalexception'):
# EvalException is present in the WSGI stack
expected = False
for expect in environ.get('paste.expected_exceptions', []):
if isinstance(e, expect):
expected = True
if not expected:
# An unexpected exception: save state for EvalException
restorer.save_registry_state(environ)
reg.cleanup()
raise
except:
# Save state for EvalException if it's present
if environ.get('paste.evalexception'):
restorer.save_registry_state(environ)
reg.cleanup()
raise
else:
reg.cleanup()
return app_iter
def streaming_iter(self, reg, environ, start_response):
try:
for item in self.application(environ, start_response):
yield item
except Exception, e:
# Regardless of if the content is an iterable, generator, list
# or tuple, we clean-up right now. If its an iterable/generator
# care should be used to ensure the generator has its own ref
# to the actual object
if environ.get('paste.evalexception'):
# EvalException is present in the WSGI stack
expected = False
for expect in environ.get('paste.expected_exceptions', []):
if isinstance(e, expect):
expected = True
if not expected:
# An unexpected exception: save state for EvalException
restorer.save_registry_state(environ)
reg.cleanup()
raise
except:
# Save state for EvalException if it's present
if environ.get('paste.evalexception'):
restorer.save_registry_state(environ)
reg.cleanup()
raise
else:
reg.cleanup()
class StackedObjectRestorer(object):
"""Track StackedObjectProxies and their proxied objects for automatic
restoration within EvalException's interactive debugger.
An instance of this class tracks all StackedObjectProxy state in existence
when unexpected exceptions are raised by WSGI applications housed by
EvalException and RegistryManager. Like EvalException, this information is
stored for the life of the process.
When an unexpected exception occurs and EvalException is present in the
WSGI stack, save_registry_state is intended to be called to store the
Registry state and enable automatic restoration on all currently registered
StackedObjectProxies.
With restoration enabled, those StackedObjectProxies' _current_obj
(overwritten by _current_obj_restoration) method's strategy is modified:
it will return its appropriate proxied object from the restorer when
a restoration context is active in the current thread.
The StackedObjectProxies' _push/pop_object methods strategies are also
changed: they no-op when a restoration context is active in the current
thread (because the pushing/popping work is all handled by the
Registry/restorer).
The request's Registry objects' reglists are restored from the restorer
when a restoration context begins, enabling the Registry methods to work
while their changes are tracked by the restorer.
The overhead of enabling restoration is negligible (another threadlocal
access for the changed StackedObjectProxy methods) for normal use outside
of a restoration context, but worth mentioning when combined with
StackedObjectProxies normal overhead. Once enabled it does not turn off,
however:
o Enabling restoration only occurs after an unexpected exception is
detected. The server is likely to be restarted shortly after the exception
is raised to fix the cause
o StackedObjectRestorer is only enabled when EvalException is enabled (not
on a production server) and RegistryManager exists in the middleware
stack"""
def __init__(self):
# Registries and their saved reglists by request_id
self.saved_registry_states = {}
self.restoration_context_id = threadinglocal.local()
def save_registry_state(self, environ):
"""Save the state of this request's Registry (if it hasn't already been
saved) to the saved_registry_states dict, keyed by the request's unique
identifier"""
registry = environ.get('paste.registry')
if not registry or not len(registry.reglist) or \
self.get_request_id(environ) in self.saved_registry_states:
# No Registry, no state to save, or this request's state has
# already been saved
return
self.saved_registry_states[self.get_request_id(environ)] = \
(registry, registry.reglist[:])
# Tweak the StackedObjectProxies we want to save state for -- change
# their methods to act differently when a restoration context is active
# in the current thread
for reglist in registry.reglist:
for stacked, obj in reglist.itervalues():
self.enable_restoration(stacked)
def get_saved_proxied_obj(self, stacked, request_id):
"""Retrieve the saved object proxied by the specified
StackedObjectProxy for the request identified by request_id"""
# All state for the request identified by request_id
reglist = self.saved_registry_states[request_id][1]
# The top of the stack was current when the exception occurred
stack_level = len(reglist) - 1
stacked_id = id(stacked)
while True:
if stack_level < 0:
# Nothing registered: Call _current_obj_orig to raise a
# TypeError
return stacked._current_obj_orig()
context = reglist[stack_level]
if stacked_id in context:
break
# This StackedObjectProxy may not have been registered by the
# RegistryManager that was active when the exception was raised --
# continue searching down the stack until it's found
stack_level -= 1
return context[stacked_id][1]
def enable_restoration(self, stacked):
"""Replace the specified StackedObjectProxy's methods with their
respective restoration versions.
_current_obj_restoration forces recovery of the saved proxied object
when a restoration context is active in the current thread.
_push/pop_object_restoration avoid pushing/popping data
(pushing/popping is only done at the Registry level) when a restoration
context is active in the current thread"""
if '_current_obj_orig' in stacked.__dict__:
# Restoration already enabled
return
for func_name in ('_current_obj', '_push_object', '_pop_object'):
orig_func = getattr(stacked, func_name)
restoration_func = getattr(stacked, func_name + '_restoration')
stacked.__dict__[func_name + '_orig'] = orig_func
stacked.__dict__[func_name] = restoration_func
def get_request_id(self, environ):
"""Return a unique identifier for the current request"""
return id(environ)
def restoration_begin(self, request_id):
"""Enable a restoration context in the current thread for the specified
request_id"""
if request_id in self.saved_registry_states:
# Restore the old Registry object's state
registry, reglist = self.saved_registry_states[request_id]
registry.reglist = reglist
self.restoration_context_id.request_id = request_id
def restoration_end(self):
"""Register a restoration context as finished, if one exists"""
try:
del self.restoration_context_id.request_id
except AttributeError:
pass
def in_restoration(self):
"""Determine if a restoration context is active for the current thread.
Returns the request_id it's active for if so, otherwise False"""
return getattr(self.restoration_context_id, 'request_id', False)
restorer = StackedObjectRestorer()
# Paste Deploy entry point
def make_registry_manager(app, global_conf):
return RegistryManager(app)
make_registry_manager.__doc__ = RegistryManager.__doc__
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/api.py 0000644 0001750 0001750 00000000026 11175375027 021344 0 ustar zack zack from tw.core import *
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/__init__.py 0000644 0001750 0001750 00000000070 11175375027 022331 0 ustar zack zack __import__('pkg_resources').declare_namespace(__name__)
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/ 0000755 0001750 0001750 00000000000 11224437421 023405 5 ustar zack zack python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/__init__.py 0000644 0001750 0001750 00000000000 11175375027 025514 0 ustar zack zack python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/ 0000755 0001750 0001750 00000000000 11224437421 026563 5 ustar zack zack python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tests/ 0000755 0001750 0001750 00000000000 11224437421 027725 5 ustar zack zack ././@LongLink 0000000 0000000 0000000 00000000156 00000000000 011567 L ustar root root python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tests/test_widget.py_tmpl python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tests/test_widge0000644 0001750 0001750 00000001160 11175375027 032014 0 ustar zack zack from tw.core.testutil import WidgetTestCase
from tw.${package} import *
class TestWidget(WidgetTestCase):
# place your widget at the TestWidget attribute
TestWidget = ${package.capitalize()}
# Initilization args. go here
widget_kw = {}
def test_render(self):
# Asserts 'foo' and 'test' (the test widget's id) appear in rendered
# string when 'foo' is passed as value to render
self.assertInOutput(['foo', 'test'], "foo")
# Asserts 'ohlalala' does not appear in rendered string when render
# is called without args
self.assertNotInOutput(['ohlalala'])
././@LongLink 0000000 0000000 0000000 00000000153 00000000000 011564 L ustar root root python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tests/__init__.py_tmpl python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tests/__init__.p0000644 0001750 0001750 00000000000 11175375027 031643 0 ustar zack zack python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/setup.cfg_tmpl 0000644 0001750 0001750 00000000106 11175375027 031445 0 ustar zack zack [egg_info]
tag_build = dev
tag_date = true
[nosetests]
where = tests
././@LongLink 0000000 0000000 0000000 00000000145 00000000000 011565 L ustar root root python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/MANIFEST.in_tmpl python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/MANIFEST.in_tmpl0000644 0001750 0001750 00000000125 11175375027 031363 0 ustar zack zack recursive-include tw/${package}/templates *
recursive-include tw/${package}/static *
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/+egg+.egg-info/ 0000755 0001750 0001750 00000000000 11224437421 031145 5 ustar zack zack ././@LongLink 0000000 0000000 0000000 00000000166 00000000000 011570 L ustar root root python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/+egg+.egg-info/paster_plugins.txt python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/+egg+.egg-info/p0000644 0001750 0001750 00000000000 11175375027 031325 0 ustar zack zack python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tw/ 0000755 0001750 0001750 00000000000 11224437421 027215 5 ustar zack zack ././@LongLink 0000000 0000000 0000000 00000000150 00000000000 011561 L ustar root root python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tw/__init__.py_tmpl python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tw/__init__.py_t0000644 0001750 0001750 00000000070 11175375027 031656 0 ustar zack zack __import__('pkg_resources').declare_namespace(__name__)
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tw/+package+/ 0000755 0001750 0001750 00000000000 11224437421 030736 5 ustar zack zack ././@LongLink 0000000 0000000 0000000 00000000161 00000000000 011563 L ustar root root python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tw/+package+/release.py_tmpl python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tw/+package+/rel0000644 0001750 0001750 00000000641 11175375027 031454 0 ustar zack zack # Metadata for the widget EGG. Should leave it for the (unimplemented) widget
# tracker to track it
__DISTRIBUTION__ = ${repr(project)|empty}
__DESCRIPTION__ = ${repr(description)|empty}
__URL__ = ${repr(url)|empty}
__VERSION__ = ${repr(version)|empty}
__AUTHOR__ = ${repr(author)|empty}
__EMAIL__ = ${repr(author_email)|empty}
__COPYRIGHT__ = "Copyright ${year} ${author}"
__LICENSE__ = ${repr(license_name)|empty}
././@LongLink 0000000 0000000 0000000 00000000162 00000000000 011564 L ustar root root python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tw/+package+/__init__.py_tmpl python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tw/+package+/__i0000644 0001750 0001750 00000000026 11175375027 031415 0 ustar zack zack from widgets import *
././@LongLink 0000000 0000000 0000000 00000000161 00000000000 011563 L ustar root root python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tw/+package+/samples.py_tmpl python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tw/+package+/sam0000644 0001750 0001750 00000000762 11175375027 031456 0 ustar zack zack """
Here you can create samples of your widgets by providing default parameters,
inserting them in a container widget, mixing them with other widgets, etc...
These samples will appear in the WidgetBrowser
See http://toscawidgets.org/documentation/WidgetBrowser for more information
"""
from tw.${package} import ${package.capitalize()}
class Demo${package.capitalize()}(${package.capitalize()}):
# Provide default parameters, value, etc... here
# default =
pass
././@LongLink 0000000 0000000 0000000 00000000161 00000000000 011563 L ustar root root python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tw/+package+/widgets.py_tmpl python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/tw/+package+/wid0000644 0001750 0001750 00000002661 11175375027 031461 0 ustar zack zack from tw.api import Widget, JSLink, CSSLink
__all__ = ["${package.capitalize()}"]
# declare your static resources here
## JS dependencies can be listed at 'javascript' so they'll get included
## before
# my_js = JSLink(modname=__name__,
# filename='static/${package}.js', javascript=[])
# my_css = CSSLink(modname=__name__, filename='static/${package}.css')
class ${package.capitalize()}(Widget):
template = """
$${value}
"""
## You can also define the template in a separate package and refer to it
## using Buffet style uris
#template = "tw.${package}.templates.${package}"
#javascript = [my_js]
#css = [my_css]
def __init__(self, id=None, parent=None, children=[], **kw):
"""Initialize the widget here. The widget's initial state shall be
determined solely by the arguments passed to this function; two
widgets initialized with the same args. should behave in *exactly* the
same way. You should *not* rely on any external source to determine
initial state."""
super(${package.capitalize()}, self).__init__(id, parent, children, **kw)
def update_params(self, d):
"""This method is called every time the widget is displayed. It's task
is to prepare all variables that are sent to the template. Those
variables can accessed as attributes of d."""
super(${package.capitalize()}, self).update_params(d)
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/setup.py_tmpl 0000644 0001750 0001750 00000002373 11175375027 031346 0 ustar zack zack import os
import sys
from setuptools import setup, find_packages
execfile(os.path.join("tw", "${package}", "release.py"))
setup(
name=__DISTRIBUTION__,
version=__VERSION__,
description=__DESCRIPTION__,
author=__AUTHOR__,
author_email=__EMAIL__,
url=__URL__,
install_requires=[
"ToscaWidgets",
## Add other requirements here
# "Genshi",
],
packages=find_packages(exclude=['ez_setup', 'tests']),
namespace_packages = ['tw'],
zip_safe=False,
include_package_data=True,
test_suite = 'nose.collector',
entry_points="""
[toscawidgets.widgets]
# Register your widgets so they can be listed in the WidgetBrowser
widgets = tw.${package}
samples = tw.${package}.samples
""",
keywords = [
'toscawidgets.widgets',
],
classifiers = [
'Development Status :: 3 - Alpha',
'Environment :: Web Environment',
'Environment :: Web Environment :: ToscaWidgets',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: Software Development :: Widget Sets',
'Intended Audience :: Developers',
'Operating System :: OS Independent',
'Programming Language :: Python',
],
)
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/docs/ 0000755 0001750 0001750 00000000000 11224437421 027513 5 ustar zack zack ././@LongLink 0000000 0000000 0000000 00000000146 00000000000 011566 L ustar root root python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/docs/conf.py_tmpl python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/docs/conf.py_tmp0000644 0001750 0001750 00000011734 11175375027 031710 0 ustar zack zack # -*- coding: utf-8 -*-
#
# Fooo documentation build configuration file, created by
# sphinx-quickstart on Wed May 14 19:27:33 2008.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# The contents of this file are pickled, so don't put values in the namespace
# that aren't pickleable (module imports are okay, they're removed automatically).
#
# All configuration values have a default value; values that are commented out
# serve to show the default value.
import sys, os
import pkg_resources
execfile(os.path.join("..", "tw", "${package}", "release.py"))
# If your extensions are in another directory, add it here. If the directory
# is relative to the documentation root, use os.path.abspath to make it
# absolute, like shown here.
#sys.path.append(os.path.abspath('some/directory'))
# General configuration
# ---------------------
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc']
# Try to add WidgetBrowser's extension if installed
try:
from widgetbrowser import sphinx_ext
extensions.append('widgetbrowser.sphinx_ext')
except ImportError:
print >> sys.stderr, "WidgetBrowser is not available..."
# Add any paths that contain templates here, relative to this directory.
templates_path = []
# The suffix of source filenames.
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General substitutions.
project = __DISTRIBUTION__
copyright = __COPYRIGHT__
# The default replacements for |version| and |release|, also used in various
# other places throughout the built documents.
#
# The short X.Y version.
version = __VERSION__
# The full version, including alpha/beta/rc tags.
release = pkg_resources.get_distribution(__DISTRIBUTION__).version
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# Options for HTML output
# -----------------------
# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
# given in html_static_path.
html_style = 'default.css'
# The name for this set of Sphinx documents. If None, it defaults to
# " v documentation".
#html_title = None
# The name of an image file (within the static path) to place at the top of
# the sidebar.
#html_logo = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
# If true, the reST sources are included in the HTML build as _sources/.
#html_copy_source = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a tag referring to it.
#html_use_opensearch = False
# Output file base name for HTML help builder.
htmlhelp_basename = __DISTRIBUTION__ + 'doc'
# Options for LaTeX output
# ------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, document class [howto/manual]).
latex_documents = [
('index',
__DISTRIBUTION__+ '.tex',
__DISTRIBUTION__ + ' Documentation',
__AUTHOR__,
'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True
././@LongLink 0000000 0000000 0000000 00000000150 00000000000 011561 L ustar root root python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/docs/index.rst_tmpl python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/widget_template/docs/index.rst_t0000644 0001750 0001750 00000001356 11175375027 031714 0 ustar zack zack .. ${project} documentation master file.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to ${project} documentation!
=========================================================
Contents
--------
.. toctree::
:maxdepth: 2
:class:`tw.${package}.${package.capitalize()}`
----------------------------------------------------------
.. autoclass:: tw.${package}.${package.capitalize()}
.. widgetbrowser:: tw.${package}.${package.capitalize()}
.. note::
See http://toscawidgets.org/documentation/WidgetBrowser to learn how to
customize the ``widgetbrowser`` directive.
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/paste_templates/__init__.pyc 0000644 0001750 0001750 00000000227 11203375526 025666 0 ustar zack zack ³ò
úõIc @ s d S( N( ( ( ( s@ /Users/cperkins1/nrel/pdil/src/tw/tw/paste_templates/__init__.pys s python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/release.py 0000644 0001750 0001750 00000000603 11224437176 022213 0 ustar zack zack from datetime import date
__all__ = [
'__VERSION__',
'__COPYRIGHT__',
'__AUTHOR__',
'__LICENSE__',
'__PACKAGE_NAME__',
]
__PACKAGE_NAME__ = "ToscaWidgets"
__VERSION__ = "0.9.7.2"
__AUTHOR__ = "Alberto Valverde Gonzalez"
__EMAIL__ = "alberto@toscat.net"
__COPYRIGHT__ = "2006-%d Alberto Valverde Gonzalez and contributors" % date.today().year
__LICENSE__ = "MIT"
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/mods/ 0000755 0001750 0001750 00000000000 11224437421 021155 5 ustar zack zack python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/mods/cp2.py 0000644 0001750 0001750 00000006520 11175375027 022226 0 ustar zack zack from pkg_resources import require
require("CherryPy <3.0")
import os, logging
import pprint
import cherrypy
from cherrypy.filters.basefilter import BaseFilter
import tw
from tw.core import resource_injector, resources
from tw.core.registry import Registry
log = logging.getLogger(__name__)
def _extract_config():
from cherrypy.config import configs
c = configs.get('global', {}).copy()
c.update(configs['/'])
return c
class TWInitFilter(BaseFilter):
"""Sort-of-emulates TWWidgetsMiddleware + Paste's RegsitryManager. Takes
care of preparing the hostframework for a request."""
def __init__(self, host_framework, prefix='/toscawidgets',
serve_files=True):
self.serve_files = serve_files
self.prefix = prefix
self.host_framework = host_framework
def on_start_resource(self):
log.debug("TWFilter: on_start_resource")
environ = cherrypy.request.wsgi_environ
registry = environ.setdefault('paste.registry', Registry())
environ['toscawidgets.prefix'] = self.prefix
registry.prepare()
registry.register(tw.framework, self.host_framework)
self.host_framework.start_request(environ)
def before_main(self):
"""Intercepts requests for static files and serves them."""
if not self.serve_files:
return
req, resp = cherrypy.request, cherrypy.response
path = req.path
if path.startswith(self.host_framework.webpath):
path = path[len(self.host_framework.webpath):]
if path.startswith(self.prefix):
reg = resources.registry
path = path[len(self.prefix)+len(reg.prefix):]
stream, ct, enc = reg.get_stream_type_encoding(path)
if stream:
resp.body = stream
if ct:
if enc:
ct += '; charset=' + enc
resp.headers['Content-Type'] = ct
req.execute_main = False
def before_finalize(self):
# Injects resources
log.debug("TWFilter: before_finalize")
response = cherrypy.response
ct = response.headers.get('content-type', 'text/html').lower()
if 'html' in ct:
cs = resource_injector.find_charset(ct)
html = ''.join(response.body)
resources = tw.framework.pop_resources()
log.debug("Injecting Resources:")
map(log.debug, pprint.pformat(resources).split('\n'))
html = resource_injector.inject_resources(html=html,
resources=resources,
encoding=cs)
response.body = [html]
# Delete Content-Length header so finalize() recalcs it.
response.headers.pop("Content-Length", None)
def on_end_resource(self):
log.debug("TWFilter: on_end_resource")
try:
environ = cherrypy.request.wsgi_environ
self.host_framework.end_request(environ)
finally:
registry = environ['paste.registry']
registry.cleanup()
def start_extension(host_framework, **filter_args):
cherrypy.root._cp_filters.append(TWInitFilter(host_framework,
**filter_args))
log.info("Added TWInitFilter")
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/mods/__init__.py 0000644 0001750 0001750 00000000070 11175375027 023273 0 ustar zack zack __import__('pkg_resources').declare_namespace(__name__)
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/mods/pylonshf.py 0000644 0001750 0001750 00000014027 11175375027 023405 0 ustar zack zack import logging
from decorator import decorator
from tw.api import retrieve_resources
from tw.mods.base import HostFramework
from tw.core.view import EngineManager
import pylons
from pylons.util import AttribSafeContextObj, ContextObj
from pylons.i18n import ugettext
from pylons.templating import render
from formencode import Invalid
__all__ = ["PylonsHostFramework", "validate", "render_response", "render",
"valid"]
log = logging.getLogger(__name__)
class PylonsHostFramework(HostFramework):
"""HostFramework object for Pylons.
Based on customization done in: http://wiki.pylonshq.com/display/pylonscookbook/An+Alternative+ToscaWidgets+Setup+with+Mako
"""
def __init__(self, engines=None, default_view='mako', translator=ugettext,
template_paths=[], engine_options=None):
if engines is None:
opts = engine_options or {}
opts.setdefault('mako.directories', template_paths)
evf = opts.pop('extra_vars_func', None)
engines = EngineManager(extra_vars_func=evf, options=opts)
super(PylonsHostFramework, self).__init__(engines, default_view,
translator)
def validate(form=None, validators=None, error_handler=None, post_only=True,
state_factory=None):
"""This decorator will use valid() to automatically validate input.
If validation is successful the decorated function will be called and the
valid result dict will be saved as ``self.form_result``.
Otherwise, the action will be re-run as if it was a GET without setting
``form_result`` and if the form is redisplayed it will display errors and
previous input values.
If the decorated method did not originally display the
form, then ``error_handler`` should be the name of the method (in the same
controller) that originally displayed it.
If you'd like validate to also check GET (query) variables during its
validation, set the ``post_only`` keyword argument to False.
"""
def wrapper(func, self, *args, **kwargs):
"""Decorator Wrapper function"""
if not valid(self, form=form, validators=validators,
post_only=post_only,
state_factory=state_factory):
if error_handler:
environ = pylons.request.environ
environ['REQUEST_METHOD'] = 'GET'
environ['pylons.routes_dict']['action'] = error_handler
return self._dispatch_call()
return func(self, *args, **kwargs)
return decorator(wrapper)
def valid(controller, form=None, validators=None, post_only=True,
state_factory=None):
"""Validate input using a ToscaWidgetsForms form.
Given a TW form or dict of validators, valid() will attempt to validate
the form or validator dict as long as a POST request is made. No
validation is performed on GET requests unless post_only is False.
If validation was succesfull, the valid result dict will be saved
as ``controller.form_result`` and valid() will return True.
Otherwise the invalid exception will be stored at
``controller.validation_exception`` and valid() will return False.
If you'd like validate to also check GET (query) variables during its
validation, set the ``post_only`` keyword argument to False.
"""
request = pylons.request._current_obj()
if post_only:
params = request.POST.copy()
else:
params = request.params.copy()
errors = {}
if state_factory:
state = state_factory()
else:
from tw import framework
# Pass registered translator for formencode
state = type('State', (object,),
{'_':staticmethod(framework.translator)})
if form:
try:
controller.form_result = form.validate(params, state=state)
except Invalid, e:
log.debug("Validation failed with:\n%s", e)
controller.validation_exception = e
errors = e.error_dict or e
if validators:
if isinstance(validators, dict):
if not hasattr(controller, 'form_result'):
controller.form_result = {}
for field, validator in validators.iteritems():
try:
controller.form_result[field] = \
validator.to_python(decoded[field] or None, state)
except Invalid, error:
errors[field] = error
if errors:
controller.errors = errors
return False
return True
# Note: render and render_response are DEPRECATED
def _render_func_wrapper(func):
def wrapper(*args, **kargs):
import warnings
warnings.warn(("%s is deprecated since collecting resources from "
"widgets at pylons.c.w is no longer needed to inject "
"them in the page.") % func.func_name,
DeprecationWarning, 2)
from tw import framework
if len(args) > 1 and args[0] in framework.engines:
framework.default_view = args[0]
global_widgets = getattr(pylons.g, 'w', None)
request_widgets = getattr(pylons.c, 'w', None)
other_resources = kargs.pop('resources', None)
pylons.c.resources = retrieve_resources(
[global_widgets, request_widgets, other_resources]
)
return func(*args, **kargs)
try:
wrapper.func_name = func.func_name
except TypeError:
# support 2.3
pass
tw_extra_doc = """\
This version is a ToscaWidgets wrapper which collects resources in
pylons.g.w and pylons.g.c and makies them available at pylons.c.resources
so the base template can render them.
It also sets the default_view if the engine name is overrided when calling me.
"""
wrapper.__doc__ = func.__doc__ + "\n\n" + tw_extra_doc
wrapper.__dict__ = func.__dict__
return wrapper
render_response = _render_func_wrapper(pylons.templating.render_response)
render = _render_func_wrapper(pylons.templating.render)
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/mods/tg.py 0000644 0001750 0001750 00000004405 11175375027 022154 0 ustar zack zack from pkg_resources import require, VersionConflict
import os, logging
# TurboGears-1.0 uses CherryPy-2.3 while TurboGears-1.5 uses CherryPy-3.1.
# CherryPy-2.3 uses Filters while CherryPy-3.1 uses Tools. We put the CherryPy
# specific code in separate files which makes it possible for CherryPy users
# that are not using TurboGears to use them directly.
try:
require("TurboGears>=1.0, <=1.5")
import cp2 as cp
default_view = 'kid'
except VersionConflict:
require("TurboGears>=1.5a1dev, <=2.0")
import cp3 as cp
default_view = 'genshi'
import turbogears
from turbogears.i18n.tg_gettext import gettext
from turbogears.view import stdvars
import cherrypy
import tw
from tw.core import view
from tw.core.util import install_framework
from tw.mods.base import HostFramework
install_framework()
log = logging.getLogger(__name__)
class TurboGears(HostFramework):
@property
def request_local(self):
try:
rl = cherrypy.request.tw_request_local
except AttributeError:
rl = self.request_local_class(cherrypy.request.wsgi_environ)
cherrypy.request.tw_request_local = rl
return rl
def start_request(self, environ):
self.request_local.default_view = self._default_view
def url(self, url):
"""
Returns the absolute path for the given url.
"""
prefix = self.request_local.environ['toscawidgets.prefix']
return '/' + turbogears.url(prefix+url).lstrip('/')
def start_extension():
if not cherrypy.config.get('toscawidgets.on', False):
return
engines = view.EngineManager()
engines.load_all(cp._extract_config(), stdvars)
host_framework = TurboGears(
engines = engines,
default_view = cherrypy.config.get('tg.defaultview', default_view),
translator = gettext,
)
prefix = cherrypy.config.get('toscawidgets.prefix', '/toscawidgets')
host_framework.prefix = prefix
host_framework.webpath = cherrypy.config.get('server.webpath', '')
log.info("Loaded TW TurboGears HostFramework")
filter_args = dict(
prefix = prefix,
serve_files = cherrypy.config.get('toscawidgets.serve_files', 1)
)
cp.start_extension(host_framework, **filter_args)
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/mods/cp3.py 0000644 0001750 0001750 00000007522 11175375027 022232 0 ustar zack zack from pkg_resources import require
require("CherryPy >=3.0")
import os, logging
import pprint
import cherrypy
import tw
from tw.core import resource_injector, resources
from tw.core.registry import Registry
log = logging.getLogger(__name__)
def _extract_config():
c = cherrypy.config.copy()
return c
class TWTool(cherrypy.Tool):
"""Sort-of-emulates TWWidgetsMiddleware + Paste's RegsitryManager. Takes
care of preparing the hostframework for a request."""
def __init__(self, host_framework, prefix='/toscawidgets',
serve_files=True):
self.serve_files = serve_files
self.prefix = prefix
self.host_framework = host_framework
return super(TWTool, self).__init__("on_start_resource", self.on_start_resource)
def on_start_resource(self):
log.debug("TWTool: on_start_resource")
environ = cherrypy.request.wsgi_environ
registry = environ.setdefault('paste.registry', Registry())
environ['toscawidgets.prefix'] = self.prefix
registry.prepare()
registry.register(tw.framework, self.host_framework)
self.host_framework.start_request(environ)
def before_request_body(self):
"""Intercepts requests for static files and serves them."""
if not self.serve_files:
return
req, resp = cherrypy.request, cherrypy.response
path = req.path_info
if path.startswith(self.host_framework.webpath):
path = path[len(self.host_framework.webpath):]
if path.startswith(self.prefix):
reg = resources.registry
path = path[len(self.prefix)+len(reg.prefix):]
stream, ct, enc = reg.get_stream_type_encoding(path)
if stream:
resp.body = stream
if ct:
if enc:
ct += '; charset=' + enc
resp.headers['Content-Type'] = ct
req.process_request_body = False
req.handler = None
def before_finalize(self):
# Injects resources
log.debug("TWTool: before_finalize")
response = cherrypy.response
ct = response.headers.get('content-type', 'text/html').lower()
if 'html' in ct:
cs = resource_injector.find_charset(ct)
html = ''.join(response.body)
resources = tw.framework.pop_resources()
log.debug("Injecting Resources:")
map(log.debug, pprint.pformat(resources).split('\n'))
html = resource_injector.inject_resources(html=html,
resources=resources,
encoding=cs)
response.body = [html]
# Delete Content-Length header so finalize() recalcs it.
response.headers.pop("Content-Length", None)
def on_end_request(self):
log.debug("TWTool: on_end_request")
try:
environ = cherrypy.request.wsgi_environ
self.host_framework.end_request(environ)
finally:
registry = environ.get('paste.registry', None)
if registry:
registry.cleanup()
def _setup(self):
conf = self._merged_args()
p = conf.pop("priority", None)
if p is None:
p = getattr(self.callable, "priority", self._priority)
cherrypy.request.hooks.attach(self._point, self.callable, priority=p, **conf)
cherrypy.request.hooks.attach('on_end_request', self.on_end_request)
cherrypy.request.hooks.attach('before_request_body', self.before_request_body)
cherrypy.request.hooks.attach('before_finalize', self.before_finalize)
def start_extension(host_framework, **filter_args):
cherrypy.tools.toscawidgets = TWTool(host_framework=host_framework, **filter_args)
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/mods/base.py 0000644 0001750 0001750 00000007450 11175653301 022451 0 ustar zack zack from tw.core.view import EngineManager
from tw.core.util import RequestLocalDescriptor, disable_runtime_checks
from tw.core.registry import StackedObjectProxy, Registry
__all__ = ["HostFramework"]
class RequestLocal(object):
def __init__(self, environ):
self.environ = environ
self.resources = {}
class HostFramework(object):
"""
This class is the interface between ToscaWidgets and the framework or
web application that's using them.
The an instance of this class should be passed as second argument to
:class:`tw.core.middleware.ToscaWidgetsMiddleware` which will call its
:meth:`start_request` method at the beginning of every
request and :meth:`end_request` when the request is over so I have a chance
to register our per-request context.
A request-local proxy to a configured instance is placed at the beginning
of the request at :attr:`tw.framework`
**Constructor's arguments:**
engines
An instance of :class:`tw.core.viewEngineManager`.
default_view
The name of the template engine used by default in the container app's
templates. It's used to determine what conversion is neccesary when
displaying root widgets on a template.
translator
Function used to translate strings.
enable_runtime_checks
Enables runtime checks for possible programming errors regarding
modifying widget attributes once a widget has been initialized.
Disabling this option can significantly reduce Widget initializatio
time.
.. note::
This operation modifies the Widget class and will affect any
application using ToscaWidgets in the same process.
"""
request_local = StackedObjectProxy(name="ToscaWidgets per-request storage")
request_local_class = RequestLocal
default_view = RequestLocalDescriptor('default_view', 'toscawidgets')
def __init__(self, engines=None, default_view='toscawidgets',
translator=lambda s: s, enable_runtime_checks=True, default_engine=None):
if engines is None:
engines = EngineManager()
self.engines = engines
self._default_view = default_view
self._default_engine = default_engine
if default_engine is None:
self._default_engine = default_view
self.translator = translator
if not enable_runtime_checks:
disable_runtime_checks()
def start_request(self, environ):
"""
Called by the middleware when a request has just begun so I have a
chance to register the request context Widgets will use for various
things.
"""
registry = environ['paste.registry']
registry.register(self.request_local, self.request_local_class(environ))
self.request_local.default_view = self._default_view
def end_request(self, environ):
"""
Called by the middleware when a request has just finished so I can
clean up.
"""
pass
def url(self, url):
"""
Returns the absolute path for the given url.
"""
prefix = self.request_local.environ['toscawidgets.prefix']
script_name = self.request_local.environ['SCRIPT_NAME']
return ''.join([script_name, prefix, url])
def register_resources(self, resources):
"""
Registers resources for injection in the current request.
"""
from tw.api import merge_resources
merge_resources(self.request_local.resources, resources)
def pop_resources(self):
"""
Returns returns the resources that have been registered for this
request and removes them from request-local storage area.
"""
resources = self.request_local.resources
self.request_local.resources = {}
return resources
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/tw/mods/wsgi.py 0000644 0001750 0001750 00000000216 11175375027 022507 0 ustar zack zack from tw.mods.base import HostFramework
__all__ = ["WSGIHostFramework"]
#TODO: Deprecate WSGIHostFramework
WSGIHostFramework = HostFramework
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/MANIFEST.in 0000644 0001750 0001750 00000000047 11175375026 021327 0 ustar zack zack recursive-include tw/paste_templates *
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/setup.py 0000644 0001750 0001750 00000006320 11175375026 021303 0 ustar zack zack """Setuptools setup file"""
import sys, os
from setuptools import setup
if sys.version_info < (2, 4):
raise SystemExit("Python 2.4 or later is required ATM")
execfile(os.path.join("tw", "release.py"))
def get_description(fname='README.txt'):
# Adapted from PEAK-Rules' setup.py
# Get our long description from the documentation
f = file(fname)
lines = []
for line in f:
if not line.strip():
break # skip to first blank line
for line in f:
if line.startswith('Documentation contents'):
break # read to "Documentation contents..."
lines.append(line)
f.close()
return ''.join(lines)
PACKAGES = [
'tw',
'tw.core',
'tw.mods',
]
# Requirements to install buffet plugins and engines
_extra_cheetah = ["Cheetah>=1.0", "TurboCheetah>=0.9.5"]
_extra_genshi = ["Genshi >= 0.3.5"]
_extra_kid = ["kid>=0.9.5", "TurboKid>=0.9.9"]
_extra_mako = ["Mako >= 0.1.1"]
# Requierements to run all tests
_extra_tests = _extra_cheetah + _extra_genshi + _extra_kid + _extra_mako + ['BeautifulSoup', 'WebTest']
setup(
name=__PACKAGE_NAME__,
version=__VERSION__,
description="Web widget creation toolkit based on TurboGears widgets",
long_description = get_description(),
install_requires=[
'WebOb',
'simplejson >= 2.0',
],
extras_require = {
'cheetah': _extra_cheetah,
'kid': _extra_kid,
'genshi': _extra_genshi,
'mako': _extra_mako,
'build_docs': [
"Sphinx",
"WidgetBrowser",
],
},
tests_require = _extra_tests,
url = "http://toscawidgets.org/",
download_url = "http://toscawidgets.org/download/",
author=__AUTHOR__,
author_email=__EMAIL__,
license=__LICENSE__,
test_suite = 'tests',
packages = PACKAGES,
namespace_packages = ['tw', 'tw.mods'],
include_package_data=True,
exclude_package_data={"thirdparty" : ["*"]},
entry_points="""
[distutils.commands]
archive_tw_resources = tw.core.command:archive_tw_resources
[python.templating.engines]
toscawidgets = tw.core.engine_plugin:ToscaWidgetsTemplatePlugin
[toscawidgets.host_frameworks]
wsgi = tw.mods.wsgi:WSGIHostFramework
pylons = tw.mods.pylonshf:PylonsHostFramework
turbogears = tw.mods.tg:Turbogears
[toscawidgets.widgets]
widgets = tw.api
resources = tw.api
[paste.paster_create_template]
toscawidgets=tw.paste_template:ToscaWidgetsTemplate
[turbogears.extensions]
toscawidgets=tw.mods.tg
[paste.filter_app_factory]
middleware = tw.api:make_middleware
""",
zip_safe=False,
classifiers = [
'Development Status :: 4 - Beta',
'Environment :: Web Environment',
'Environment :: Web Environment :: ToscaWidgets',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: Internet :: WWW/HTTP :: WSGI',
'Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware',
'Topic :: Software Development :: Widget Sets',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python',
],
)
python-toscawidgets-0.9.7.2/ToscaWidgets-0.9.7.2/setup.cfg 0000644 0001750 0001750 00000000141 11224437421 021376 0 ustar zack zack [egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0
[aliases]
release = egg_info -rDb ""
python-toscawidgets-0.9.7.2/toscawidgets 0000777 0001750 0001750 00000000000 11230574132 022201 2ToscaWidgets-0.9.7.2/ ustar zack zack python-toscawidgets-0.9.7.2/tw.forms-0.9.7.2/ 0000755 0001750 0001750 00000000000 11224440166 016740 5 ustar zack zack python-toscawidgets-0.9.7.2/tw.forms-0.9.7.2/PKG-INFO 0000644 0001750 0001750 00000001353 11224440166 020037 0 ustar zack zack Metadata-Version: 1.0
Name: tw.forms
Version: 0.9.7.2
Summary: Web Widgets for building and validating forms. (former ToscaWidgetsForms)
Home-page: http://toscawidgets.org
Author: Alberto Valverde Gonzalez
Author-email: alberto@toscat.net
License: MIT
Download-URL: http://toscawidgets.org/download
Description: UNKNOWN
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Environment :: Web Environment :: ToscaWidgets
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Widget Sets
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
python-toscawidgets-0.9.7.2/tw.forms-0.9.7.2/tw/ 0000755 0001750 0001750 00000000000 11224440166 017372 5 ustar zack zack python-toscawidgets-0.9.7.2/tw.forms-0.9.7.2/tw/__init__.py 0000644 0001750 0001750 00000000070 11120001754 021467 0 ustar zack zack __import__('pkg_resources').declare_namespace(__name__)
python-toscawidgets-0.9.7.2/tw.forms-0.9.7.2/tw/forms/ 0000755 0001750 0001750 00000000000 11224440166 020520 5 ustar zack zack python-toscawidgets-0.9.7.2/tw.forms-0.9.7.2/tw/forms/__init__.py 0000644 0001750 0001750 00000001102 11120001754 022612 0 ustar zack zack """
Form widgets for ToscaWidgets.
To download and install::
easy_install twForms
"""
from tw.api import Widget
from tw.forms.core import *
from tw.forms.fields import *
from tw.forms.datagrid import *
from tw.forms.calendars import *
# build all so doc tools introspect me properly
from tw.forms.core import __all__ as __core_all
from tw.forms.fields import __all__ as __fields_all
from tw.forms.datagrid import __all__ as __datagrid_all
from tw.forms.calendars import __all__ as __calendars_all
__all__ = __core_all + __fields_all + __datagrid_all + __calendars_all
python-toscawidgets-0.9.7.2/tw.forms-0.9.7.2/tw/forms/templates/ 0000755 0001750 0001750 00000000000 11224440166 022516 5 ustar zack zack python-toscawidgets-0.9.7.2/tw.forms-0.9.7.2/tw/forms/templates/select_field.html 0000644 0001750 0001750 00000000764 11120001754 026024 0 ustar zack zack
python-toscawidgets-0.9.7.2/tw.forms-0.9.7.2/tw/forms/templates/table_fieldset.html 0000644 0001750 0001750 00000004316 11211333703 026350 0 ustar zack zack
python-toscawidgets-0.9.7.2/tw.forms-0.9.7.2/tw/forms/templates/spacer.html 0000644 0001750 0001750 00000000147 11120001754 024652 0 ustar zack zack