Chris McDonough
2010-10-26 bc338f7c10d2776fb218c3a8033cf928d8ea0ce4
add dependency on mako and configure in mako templating by default
4 files added
5 files modified
258 ■■■■■ changed files
.gitignore 2 ●●●●● patch | view | raw | blame | history
pyramid/configuration.py 3 ●●●●● patch | view | raw | blame | history
pyramid/mako_templating.py 67 ●●●●● patch | view | raw | blame | history
pyramid/resource.py 8 ●●●● patch | view | raw | blame | history
pyramid/tests/fixtures/helloworld.mak 3 ●●●●● patch | view | raw | blame | history
pyramid/tests/fixtures/helloworld.mako 3 ●●●●● patch | view | raw | blame | history
pyramid/tests/test_mako_templating.py 149 ●●●●● patch | view | raw | blame | history
pyramid/tests/test_resource.py 22 ●●●●● patch | view | raw | blame | history
setup.py 1 ●●●● patch | view | raw | blame | history
.gitignore
@@ -5,3 +5,5 @@
*.txt.py
.coverage
env26
env24
pyramid/configuration.py
@@ -45,6 +45,7 @@
from pyramid import chameleon_text
from pyramid import chameleon_zpt
from pyramid.mako_templating import renderer_factory as mako_renderer_factory
from pyramid import renderers
from pyramid.renderers import RendererHelper
from pyramid.authorization import ACLAuthorizationPolicy
@@ -82,6 +83,8 @@
DEFAULT_RENDERERS = (
    ('.pt', chameleon_zpt.renderer_factory),
    ('.txt', chameleon_text.renderer_factory),
    ('.mak', mako_renderer_factory),
    ('.mako', mako_renderer_factory),
    ('json', renderers.json_renderer_factory),
    ('string', renderers.string_renderer_factory),
    )
pyramid/mako_templating.py
New file
@@ -0,0 +1,67 @@
from zope.interface import implements
from zope.interface import Interface
from mako.lookup import TemplateLookup
from pyramid.interfaces import ITemplateRenderer
from pyramid.exceptions import ConfigurationError
from pyramid.threadlocal import get_current_registry
from pyramid.settings import get_settings
from pyramid.resource import resolve_resource_spec
from pyramid.resource import abspath_from_resource_spec
class IMakoLookup(Interface):
    pass
def renderer_factory(path):
    registry = get_current_registry()
    lookup = registry.queryUtility(IMakoLookup)
    if lookup is None:
        settings = get_settings() or {}
        reload_templates = settings.get('reload_templates', False)
        directories = settings.get('mako.directories')
        module_directory = settings.get('mako.module_directory')
        input_encoding = settings.get('mako.input_encoding', 'utf-8')
        if directories is None:
            raise ConfigurationError(
                'Mako template used without a lookup path')
        directories = directories.splitlines()
        directories = [ abspath_from_resource_spec(d) for d in directories ]
        lookup = TemplateLookup(directories=directories,
                                module_directory=module_directory,
                                input_encoding=input_encoding,
                                filesystem_checks=reload_templates)
        registry.registerUtility(lookup, IMakoLookup)
    _, path = resolve_resource_spec(path)
    return MakoLookupTemplateRenderer(path, lookup)
class MakoLookupTemplateRenderer(object):
    implements(ITemplateRenderer)
    def __init__(self, path, lookup):
        self.path = path
        self.lookup = lookup
    def implementation(self):
        return self.template
    @property
    def template(self):
        return self.lookup.get_template(self.path)
    def __call__(self, value, system):
        context = system.pop('context', None)
        if context is not None:
            system['_context'] = context
        def_name = None
        if isinstance(value, tuple):
            def_name, value = value
        try:
            system.update(value)
        except (TypeError, ValueError):
            raise ValueError('renderer was passed non-dictionary as value')
        template = self.template
        if def_name is not None:
            template = template.get_def(def_name)
        result = template.render_unicode(**system)
        return result
pyramid/resource.py
@@ -198,4 +198,10 @@
                          relpath.replace(os.path.sep, '/'))
    return abspath
            
def abspath_from_resource_spec(spec, pname='__main__'):
    if pname is None:
        return spec
    pname, filename = resolve_resource_spec(spec, pname)
    if pname is None:
        return filename
    return pkg_resources.resource_filename(pname, filename)
pyramid/tests/fixtures/helloworld.mak
New file
@@ -0,0 +1,3 @@
## -*- coding: utf-8 -*-
<% a, b = 'foo', u'föö' %>
Hello ${u'föö'}
pyramid/tests/fixtures/helloworld.mako
New file
@@ -0,0 +1,3 @@
## -*- coding: utf-8 -*-
<% a, b = 'foo', u'föö' %>
Hello ${u'föö'}
pyramid/tests/test_mako_templating.py
New file
@@ -0,0 +1,149 @@
## come on python gimme some of that sweet, sweet -*- coding: utf-8 -*-
import unittest
class Base(object):
    def setUp(self):
        from pyramid.configuration import Configurator
        self.config = Configurator()
        self.config.begin()
        import os
        here = os.path.abspath(os.path.dirname(__file__))
        self.templates_dir = os.path.join(here, 'fixtures')
    def tearDown(self):
        self.config.end()
class Test_renderer_factory(Base, unittest.TestCase):
    def _callFUT(self, path):
        from pyramid.mako_templating import renderer_factory
        return renderer_factory(path)
    def test_no_directories(self):
        from pyramid.exceptions import ConfigurationError
        self.assertRaises(ConfigurationError, self._callFUT, 'path')
    def test_no_lookup(self):
        from pyramid.mako_templating import IMakoLookup
        self.config.add_settings({'mako.directories':self.templates_dir})
        renderer = self._callFUT('helloworld.mak')
        lookup = self.config.registry.getUtility(IMakoLookup)
        self.assertEqual(lookup.directories, [self.templates_dir])
        self.assertEqual(lookup.filesystem_checks, False)
        self.assertEqual(renderer.path, 'helloworld.mak')
        self.assertEqual(renderer.lookup, lookup)
    def test_composite_directories_path(self):
        from pyramid.mako_templating import IMakoLookup
        twice = self.templates_dir + '\n' + self.templates_dir
        self.config.add_settings({'mako.directories':twice})
        self._callFUT('helloworld.mak')
        lookup = self.config.registry.getUtility(IMakoLookup)
        self.assertEqual(lookup.directories, [self.templates_dir]*2)
    def test_with_lookup(self):
        from pyramid.mako_templating import IMakoLookup
        lookup = dict()
        self.config.registry.registerUtility(lookup, IMakoLookup)
        renderer = self._callFUT('helloworld.mak')
        self.assertEqual(renderer.lookup, lookup)
        self.assertEqual(renderer.path, 'helloworld.mak')
class MakoLookupTemplateRendererTests(Base, unittest.TestCase):
    def _getTargetClass(self):
        from pyramid.mako_templating import MakoLookupTemplateRenderer
        return MakoLookupTemplateRenderer
    def _makeOne(self, *arg, **kw):
        klass = self._getTargetClass()
        return klass(*arg, **kw)
    def test_instance_implements_ITemplate(self):
        from zope.interface.verify import verifyObject
        from pyramid.interfaces import ITemplateRenderer
        verifyObject(ITemplateRenderer, self._makeOne(None, None))
    def test_class_implements_ITemplate(self):
        from zope.interface.verify import verifyClass
        from pyramid.interfaces import ITemplateRenderer
        verifyClass(ITemplateRenderer, self._getTargetClass())
    def test_call(self):
        lookup = DummyLookup()
        instance = self._makeOne('path', lookup)
        result = instance({}, {'system':1})
        self.failUnless(isinstance(result, unicode))
        self.assertEqual(result, u'result')
    def test_call_with_system_context(self):
        # lame
        lookup = DummyLookup()
        instance = self._makeOne('path', lookup)
        result = instance({}, {'context':1})
        self.failUnless(isinstance(result, unicode))
        self.assertEqual(result, u'result')
        self.assertEqual(lookup.values, {'_context':1})
    def test_call_with_tuple_value(self):
        lookup = DummyLookup()
        instance = self._makeOne('path', lookup)
        result = instance(('fub', {}), {'context':1})
        self.assertEqual(lookup.deffed, 'fub')
        self.assertEqual(result, u'result')
        self.assertEqual(lookup.values, {'_context':1})
    def test_call_with_nondict_value(self):
        lookup = DummyLookup()
        instance = self._makeOne('path', lookup)
        self.assertRaises(ValueError, instance, None, {})
    def test_implementation(self):
        lookup = DummyLookup()
        instance = self._makeOne('path', lookup)
        result = instance.implementation().render_unicode()
        self.failUnless(isinstance(result, unicode))
        self.assertEqual(result, u'result')
class TestIntegration(unittest.TestCase):
    def setUp(self):
        import pyramid.mako_templating
        from pyramid.configuration import Configurator
        self.config = Configurator()
        self.config.begin()
        self.config.add_settings({'mako.directories':
                                  'pyramid.tests:fixtures'})
        self.config.add_renderer('.mak',
                                 pyramid.mako_templating.renderer_factory)
    def tearDown(self):
        self.config.end()
    def test_render(self):
        from pyramid.renderers import render
        result = render('helloworld.mak', {'a':1})
        self.assertEqual(result, u'\nHello föö\n')
    def test_render_to_response(self):
        from pyramid.renderers import render_to_response
        result = render_to_response('helloworld.mak', {'a':1})
        self.assertEqual(result.ubody, u'\nHello föö\n')
    def test_get_renderer(self):
        from pyramid.renderers import get_renderer
        result = get_renderer('helloworld.mak')
        self.assertEqual(result.implementation().render_unicode(),
                         u'\nHello föö\n')
class DummyLookup(object):
    def get_template(self, path):
        self.path = path
        return self
    def get_def(self, path):
        self.deffed = path
        return self
    def render_unicode(self, **values):
        self.values = values
        return u'result'
pyramid/tests/test_resource.py
@@ -401,7 +401,27 @@
        o = self._makeOne('foo.pt', 'package', 'bar.pt')
        result = o('notfound.pt')
        self.assertEqual(result, None)
class Test_abspath_from_resource_spec(unittest.TestCase):
    def _callFUT(self, spec, pname='__main__'):
        from pyramid.resource import abspath_from_resource_spec
        return abspath_from_resource_spec(spec, pname)
    def test_pname_is_None_before_resolve_resource_spec(self):
        result = self._callFUT('abc', None)
        self.assertEqual(result, 'abc')
    def test_pname_is_None_after_resolve_resource_spec(self):
        result = self._callFUT('/abc', '__main__')
        self.assertEqual(result, '/abc')
    def test_pkgrelative(self):
        import os
        here = os.path.dirname(__file__)
        path = os.path.abspath(here)
        result = self._callFUT('abc', 'pyramid.tests')
        self.assertEqual(result, os.path.join(path, 'abc'))
class DummyOverride:
    def __init__(self, result):
        self.result = result
setup.py
@@ -29,6 +29,7 @@
install_requires=[
    'Chameleon >= 1.2.3',
    'Mako',
    'Paste > 1.7', # temp version pin to prevent PyPi install failure :-(
    'PasteDeploy',
    'PasteScript',