Default renderer can fail to setup properly #249

Closed
mLewisLogic opened this Issue Aug 8, 2011 · 8 comments

Comments

Projects
None yet
3 participants

Situation:

init.py

default renderer setup in config

config.add_renderer(None, json_renderer_factory)

views.py

@view_config(name='a', context=AEndpoint, permission='everyone')
def a(request):
return {}

@view_config(route_name='b', renderer='api:templates/b.pt')
def b(request):
return {}

Note: A is setup on traversal, while B is dispatch
If I start the server, then load A first, everything works fine.
If I start the server, then load B first, subsequent calls to A fail with:

File '/srv/spoton/lib/python2.7/site-packages/WebError-0.10.3-py2.7.egg/weberror/evalexception.py', line 431 in respond
app_iter = self.application(environ, detect_start_response)
File '/srv/spoton/lib/python2.7/site-packages/pyramid/router.py', line 161 in call
response = view_callable(context, request)
File '/srv/spoton/lib/python2.7/site-packages/pyramid/config.py', line 3022 in _secured_view
return view(context, request)
File '/srv/spoton/lib/python2.7/site-packages/pyramid/config.py', line 3140 in rendered_view
context)
File '/srv/spoton/lib/python2.7/site-packages/pyramid/renderers.py', line 384 in render_view
return self.render_to_response(response, system, request=request)
File '/srv/spoton/lib/python2.7/site-packages/pyramid/renderers.py', line 411 in render_to_response
result = self.render(value, system_values, request=request)
File '/srv/spoton/lib/python2.7/site-packages/pyramid/renderers.py', line 387 in render
renderer = self.renderer
File '/srv/spoton/lib/python2.7/site-packages/pyramid/decorator.py', line 17 in get
val = self.wrapped(inst)
File '/srv/spoton/lib/python2.7/site-packages/pyramid/renderers.py', line 370 in renderer
'No such renderer factory %s' % str(self.type))
ValueError: No such renderer factory None

This is when running via paster. Haven't tried any other webservers.

Owner

mcdonc commented Aug 10, 2011

Sure enough, I can replicate this behavior with the following script (using the Pyramid trunk):

from pyramid.view import view_config
from pyramid.config import Configurator
from pyramid.renderers import json_renderer_factory
from paste.httpserver import serve

class Root(object):
    def __init__(self, request):
        pass

@view_config(name='a', context=Root, permission='everyone')
def a(request):
    return {}

@view_config(route_name='b', renderer='__main__:foo.pt')
def b(request):
    return {}


if __name__ == '__main__':
    config = Configurator(root_factory=Root)
    config.add_renderer(None, json_renderer_factory)
    config.add_route('b', '/b')
    config.scan('__main__')
    serve(config.make_wsgi_app())

# foo.pt in same directory:
# <html>
# </html>
Owner

mcdonc commented Aug 10, 2011

Simplified:


from pyramid.config import Configurator
from pyramid.renderers import json_renderer_factory
from paste.httpserver import serve

def a(request):
    return {}

def b(request):
    return {}

if __name__ == '__main__':
    config = Configurator()
    config.add_renderer(None, json_renderer_factory)
    config.add_route('b', '/b')
    config.add_view(a, name='a')
    config.add_view(b, route_name='b', renderer='__main__:foo.pt')
    serve(config.make_wsgi_app())

# foo.pt in same directory:
# <html>
# </html>

Note: does not fail if renderer='string' instead of renderer='main:foo.pt'

Member

cguardia commented Aug 10, 2011

Chris, I thought you meant a script for reproducing it without pyramid...sorry I made you work extra.

FWIW I did a very similar script and found out that when visiting 'b' first, the default renderer is in the registry until we get to this line:

https://github.com/Pylons/pyramid/blob/master/pyramid/renderers.py#L336

After that, the registry query for (IRenderer, None) comes empty, so a visit to 'a' fails from then on. Visiting 'a' first works because renderer is a reified property and it gets stored as an attribute after that visit.

Owner

mcdonc commented Aug 10, 2011

Yeah sorry Carlos, I didn't know what you were trying was related to Pyramid at all. No extra work got done, no worries ;) Thanks for the tip about where things go pear-shaped, that should help me track it down,

Owner

mcdonc commented Aug 10, 2011

Hilarious. Adding this line causes the problem to disappear:


[chrism@thinko pyramid]$ git diff
diff --git a/pyramid/renderers.py b/pyramid/renderers.py
index a06067c..f6e293b 100644
--- a/pyramid/renderers.py
+++ b/pyramid/renderers.py
@@ -393,6 +393,7 @@ class RendererHelper(object):
         return self.render_to_response(response, system, request=request)

     def render(self, value, system_values, request=None):
+        print self.registry.queryUtility(IRendererFactory)
         renderer = self.renderer
         if system_values is None:
             system_values = {
Owner

mcdonc commented Aug 10, 2011

The smallest fix I can come up with is this:

[chrism@thinko pyramid]$ git diff
diff --git a/pyramid/renderers.py b/pyramid/renderers.py
index a06067c..94ec74c 100644
--- a/pyramid/renderers.py
+++ b/pyramid/renderers.py
@@ -354,7 +354,7 @@ class RendererHelper(object):
         if name and '.' in name:
             rtype = os.path.splitext(name)[1]
         else:
-            rtype = name
+            rtype = name or ''

         if registry is None:
             registry = get_current_registry()

mcdonc closed this in 1939d00 Aug 10, 2011

Confirmed fix. Thanks guys!

@biosyssun biosyssun pushed a commit to biosyssun/pyramid that referenced this issue Dec 13, 2014

@mcdonc mcdonc - Fixed an issue with the default renderer not working at certain tim…
…es. See

  Pylons/pyramid#249

Closes #249.
07980e5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment