summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2012-08-29 16:08:14 -0400
committerChris McDonough <chrism@plope.com>2012-08-29 16:08:14 -0400
commit345bc79dcdbacb4cd2abd1227b5f851482511064 (patch)
tree7bb2a035dedeb89bafcc21d45fe3a6a5f6932bdc
parenta7051f17a6f352193b4f4b7f1bcc635dff452001 (diff)
parenteecaa867d72d06fec45dd151fcd2e93d02927cef (diff)
downloadpyramid-345bc79dcdbacb4cd2abd1227b5f851482511064.tar.gz
pyramid-345bc79dcdbacb4cd2abd1227b5f851482511064.tar.bz2
pyramid-345bc79dcdbacb4cd2abd1227b5f851482511064.zip
Merge branch 'feature.macrorenderers'
-rw-r--r--docs/narr/templates.rst38
-rw-r--r--pyramid/chameleon_text.py2
-rw-r--r--pyramid/chameleon_zpt.py19
-rw-r--r--pyramid/renderers.py13
-rw-r--r--pyramid/tests/test_renderers.py27
5 files changed, 85 insertions, 14 deletions
diff --git a/docs/narr/templates.rst b/docs/narr/templates.rst
index 860010a1a..adc671766 100644
--- a/docs/narr/templates.rst
+++ b/docs/narr/templates.rst
@@ -534,6 +534,30 @@ And ``templates/mytemplate.pt`` might look like so:
</span>
</html>
+
+Using A Chameleon Macro Name Within a Chameleon ZPT Template
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sommetime you'd like to render a macro inside of a Chameleon ZPT template
+instead of the full Chameleon ZPT template. To render the content of a
+``define-macro`` field inside a Chameleon ZPT template, given a Chameleon
+template file named ``foo.pt`` and a macro named ``bar`` defined within it
+(e.g. ``<div metal:define-macro="bar">...</div>``, you can configure the
+template as a :term:`renderer` like so:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+
+ @view_config(renderer='foo#bar.pt')
+ def my_view(request):
+ return {'project':'my project'}
+
+The above will render the ``bar`` macro from within the ``foo.pt`` template
+instead of the entire template.
+
+
.. index::
single: Chameleon text templates
@@ -714,12 +738,13 @@ This template doesn't use any advanced features of Mako, only the
:term:`renderer globals`. See the `the Mako documentation
<http://www.makotemplates.org/>`_ to use more advanced features.
-Using def inside Mako Templates
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Using A Mako def name Within a Renderer Name
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-To use a def inside a Mako template, given a :term:`Mako` template file named
-``foo.mak`` and a def named ``bar``, you can configure the template as a
-:term:`renderer` like so:
+Sommetime you'd like to render a ``def`` inside of a Mako template instead of
+the full Mako template. To render a def inside a Mako template, given a
+:term:`Mako` template file named ``foo.mak`` and a def named ``bar``, you can
+configure the template as a :term:`renderer` like so:
.. code-block:: python
:linenos:
@@ -730,6 +755,9 @@ To use a def inside a Mako template, given a :term:`Mako` template file named
def my_view(request):
return {'project':'my project'}
+The above will render the ``bar`` def from within the ``foo.mak`` template
+instead of the entire template.
+
.. index::
single: automatic reloading of templates
single: template automatic reload
diff --git a/pyramid/chameleon_text.py b/pyramid/chameleon_text.py
index 872d3b920..20f614857 100644
--- a/pyramid/chameleon_text.py
+++ b/pyramid/chameleon_text.py
@@ -27,7 +27,7 @@ def renderer_factory(info):
@implementer(ITemplateRenderer)
class TextTemplateRenderer(object):
- def __init__(self, path, lookup):
+ def __init__(self, path, lookup, macro=None):
self.path = path
self.lookup = lookup
diff --git a/pyramid/chameleon_zpt.py b/pyramid/chameleon_zpt.py
index aa6f89e07..22b84066b 100644
--- a/pyramid/chameleon_zpt.py
+++ b/pyramid/chameleon_zpt.py
@@ -26,25 +26,34 @@ def renderer_factory(info):
@implementer(ITemplateRenderer)
class ZPTTemplateRenderer(object):
- def __init__(self, path, lookup):
+ def __init__(self, path, lookup, macro=None):
self.path = path
self.lookup = lookup
+ self.macro = macro
@reify # avoid looking up reload_templates before manager pushed
def template(self):
if sys.platform.startswith('java'): # pragma: no cover
raise RuntimeError(
'Chameleon templates are not compatible with Jython')
- return PageTemplateFile(self.path,
- auto_reload=self.lookup.auto_reload,
- debug=self.lookup.debug,
- translate=self.lookup.translate)
+ tf = PageTemplateFile(self.path,
+ auto_reload=self.lookup.auto_reload,
+ debug=self.lookup.debug,
+ translate=self.lookup.translate)
+ if self.macro:
+ # render only the portion of the template included in a
+ # define-macro named the value of self.macro
+ macro_renderer = tf.macros[self.macro].include
+ tf._render = macro_renderer
+ return tf
def implementation(self):
return self.template
def __call__(self, value, system):
try:
+ system['renderer'] = self
+ system['template'] = self.template
system.update(value)
except (TypeError, ValueError):
raise ValueError('renderer was passed non-dictionary as value')
diff --git a/pyramid/renderers.py b/pyramid/renderers.py
index e526f9997..fe9df33d1 100644
--- a/pyramid/renderers.py
+++ b/pyramid/renderers.py
@@ -1,5 +1,6 @@
import json
import os
+import re
import pkg_resources
import threading
@@ -426,7 +427,7 @@ class ChameleonRendererLookup(object):
raise ValueError('Missing template file: %s' % spec)
renderer = registry.queryUtility(ITemplateRenderer, name=spec)
if renderer is None:
- renderer = self.impl(spec, self)
+ renderer = self.impl(spec, self, macro=None)
# cache the template
try:
self.lock.acquire()
@@ -438,6 +439,14 @@ class ChameleonRendererLookup(object):
# spec is a package:relpath asset spec
renderer = registry.queryUtility(ITemplateRenderer, name=spec)
if renderer is None:
+ p = re.compile(
+ r'(?P<asset>[\w_.:/]+)'
+ r'(?:\#(?P<defname>[\w_]+))?'
+ r'(\.(?P<ext>.*))'
+ )
+ asset, macro, ext = p.match(spec).group(
+ 'asset', 'defname', 'ext')
+ spec = '%s.%s' % (asset, ext)
try:
package_name, filename = spec.split(':', 1)
except ValueError: # pragma: no cover
@@ -450,7 +459,7 @@ class ChameleonRendererLookup(object):
if not pkg_resources.resource_exists(package_name, filename):
raise ValueError(
'Missing template asset: %s (%s)' % (spec, abspath))
- renderer = self.impl(abspath, self)
+ renderer = self.impl(abspath, self, macro=macro)
settings = info.settings
if not settings.get('reload_assets'):
# cache the template
diff --git a/pyramid/tests/test_renderers.py b/pyramid/tests/test_renderers.py
index 495d7dc23..cc3d73fb7 100644
--- a/pyramid/tests/test_renderers.py
+++ b/pyramid/tests/test_renderers.py
@@ -292,7 +292,32 @@ class TestChameleonRendererLookup(unittest.TestCase):
if path.endswith('.pyc'): # pragma: no cover
path = path[:-1]
self.assertTrue(factory.path.startswith(path))
- self.assertEqual(factory.kw, {})
+ self.assertEqual(factory.kw, {'macro':None})
+
+ def test___call__spec_withmacro(self):
+ import os
+ from pyramid import tests
+ module_name = tests.__name__
+ relpath = 'fixtures/withmacro#foo.pt'
+ renderer = {}
+ factory = DummyFactory(renderer)
+ spec = '%s:%s' % (module_name, relpath)
+ info = DummyRendererInfo({
+ 'name':spec,
+ 'package':None,
+ 'registry':self.config.registry,
+ 'settings':{},
+ 'type':'type',
+ })
+ lookup = self._makeOne(factory)
+ result = lookup(info)
+ self.assertTrue(result is renderer)
+ path = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ 'fixtures',
+ 'withmacro.pt')
+ self.assertTrue(factory.path.startswith(path))
+ self.assertEqual(factory.kw, {'macro':'foo'})
def test___call__reload_assets_true(self):
import pyramid.tests