1
"""Paste Template and Pylons utility functions
3
PylonsTemplate is a Paste Template sub-class that configures the source
4
directory and default plug-ins for a new Pylons project. The minimal
5
template a more minimal template with less additional directories and
13
from paste.deploy.converters import asbool
14
from paste.script.appinstall import Installer
15
from paste.script.templates import Template, var
16
from tempita import paste_script_template_renderer
19
import pylons.configuration
22
__all__ = ['AttribSafeContextObj', 'ContextObj', 'PylonsContext',
23
'class_name_from_module_name', 'call_wsgi_application']
25
log = logging.getLogger(__name__)
27
def call_wsgi_application(application, environ, catch_exc_info=False):
29
Call the given WSGI application, returning ``(status_string,
30
headerlist, app_iter)``
32
Be sure to call ``app_iter.close()`` if it's there.
34
If catch_exc_info is true, then returns ``(status_string,
35
headerlist, app_iter, exc_info)``, where the fourth item may
36
be None, but won't be if there was an exception. If you don't
37
do this and there was an exception, the exception will be
43
def start_response(status, headers, exc_info=None):
44
if exc_info is not None and not catch_exc_info:
45
raise exc_info[0], exc_info[1], exc_info[2]
46
captured[:] = [status, headers, exc_info]
48
app_iter = application(environ, start_response)
49
if not captured or output:
51
output.extend(app_iter)
53
if hasattr(app_iter, 'close'):
57
return (captured[0], captured[1], app_iter, captured[2])
59
return (captured[0], captured[1], app_iter)
62
def class_name_from_module_name(module_name):
63
"""Takes a module name and returns the name of the class it
66
If the module name contains dashes, they are replaced with
71
>>> class_name_from_module_name('with-dashes')
73
>>> class_name_from_module_name('with_underscores')
75
>>> class_name_from_module_name('oneword')
79
words = module_name.replace('-', '_').split('_')
80
return ''.join(w.title() for w in words)
83
class PylonsContext(object):
84
"""Pylons context object
86
All the Pylons Stacked Object Proxies are also stored here, for use
87
in generators and async based operation where the globals can't be
90
This object is attached in
91
:class:`~pylons.controllers.core.WSGIController` instances as
92
:attr:`~WSGIController._py_object`. For example::
94
class MyController(WSGIController):
96
pyobj = self._py_object
97
return "Environ is %s" % pyobj.request.environ
103
class ContextObj(object):
104
"""The :term:`tmpl_context` object, with strict attribute access
105
(raises an Exception when the attribute does not exist)"""
107
attrs = sorted((name, value)
108
for name, value in self.__dict__.iteritems()
109
if not name.startswith('_'))
111
for name, value in attrs:
112
value_repr = repr(value)
113
if len(value_repr) > 70:
114
value_repr = value_repr[:60] + '...' + value_repr[-5:]
115
parts.append(' %s=%s' % (name, value_repr))
116
return '<%s.%s at %s%s>' % (
117
self.__class__.__module__,
118
self.__class__.__name__,
123
class AttribSafeContextObj(ContextObj):
124
"""The :term:`tmpl_context` object, with lax attribute access (
125
returns '' when the attribute does not exist)"""
126
def __getattr__(self, name):
128
return object.__getattribute__(self, name)
129
except AttributeError:
130
log.debug("No attribute called %s found on c object, returning "
131
"empty string", name)
135
class PylonsTemplate(Template):
136
_template_dir = ('pylons', 'templates/default_project')
137
template_renderer = staticmethod(paste_script_template_renderer)
138
summary = 'Pylons application template'
139
egg_plugins = ['PasteScript', 'Pylons']
141
var('template_engine', 'mako/genshi/jinja2/etc: Template language',
143
var('sqlalchemy', 'True/False: Include SQLAlchemy 0.5 configuration',
146
ensure_names = ['description', 'author', 'author_email', 'url']
148
def pre(self, command, output_dir, vars):
149
"""Called before template is applied."""
150
package_logger = vars['package']
151
if package_logger == 'root':
152
# Rename the app logger in the rare case a project is named 'root'
153
package_logger = 'app'
154
vars['package_logger'] = package_logger
157
vars.setdefault('template_engine',
158
pylons.configuration.default_template_engine)
160
if template_engine == 'mako':
161
# Support a Babel extractor default for Mako
162
vars['babel_templates_extractor'] = \
163
("('templates/**.mako', 'mako', {'input_encoding': 'utf-8'})"
164
",\n%s#%s" % (' ' * 4, ' ' * 8))
166
vars['babel_templates_extractor'] = ''
168
# Ensure these exist in the namespace
169
for name in self.ensure_names:
170
vars.setdefault(name, '')
172
vars['version'] = vars.get('version', '0.1')
173
vars['zip_safe'] = asbool(vars.get('zip_safe', 'false'))
174
vars['sqlalchemy'] = asbool(vars.get('sqlalchemy', 'false'))
177
class MinimalPylonsTemplate(PylonsTemplate):
178
_template_dir = ('pylons', 'templates/minimal_project')
179
summary = 'Pylons minimal application template'
181
var('template_engine', 'mako/genshi/jinja2/etc: Template language',
186
class PylonsInstaller(Installer):
188
config_file = 'config/deployment.ini_tmpl'
190
def config_content(self, command, vars):
192
Called by ``self.write_config``, this returns the text content
193
for the config file, given the provided variables.
195
modules = [line.strip()
196
for line in self.dist.get_metadata_lines('top_level.txt')
197
if line.strip() and not line.strip().startswith('#')]
199
print >> sys.stderr, 'No modules are listed in top_level.txt'
200
print >> sys.stderr, \
201
'Try running python setup.py egg_info to regenerate that file'
202
for module in modules:
203
if pkg_resources.resource_exists(module, self.config_file):
204
return self.template_renderer(
205
pkg_resources.resource_string(module, self.config_file),
206
vars, filename=self.config_file)
207
# Legacy support for the old location in egg-info
208
return super(PylonsInstaller, self).config_content(command, vars)