Pylons/pyramid — Issue #409: View lookup only checks the views registered for the first matched interface implemented by context
Author: sergeyv
Created: 2012-01-20 02:37:00+00:00
State: open

Basically, I have a resource tree, nodes of which can be either read-only, write-only, or read-write. Readable nodes implement IReader, writeable nodes implement IWriter and the read-write ones implement both interfaces.

The Pyramid documentation on view lookup states that

... All predicates must match for the associated view to be called.

This does not mean however, that Pyramid “stops looking” when it finds a view registration with
predicates that don’t match. If one set of view predicates does not match, the “next most specific”
view (if any) is consulted for predicates, and so on, until a view is found, or no view can be matched
up with the request. The first view with a set of predicates all of which match the request environment
will be invoked.

However, I'm finding that in case of interfaces, Pyramid seems to first find the first matched interface, then narrow the selection down for the views which match that interface _only_. If no views matched during that process, no further checking is made and a "predicate mismatch" error is raised.

Here's a simple application to illustrate the issue:

from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
from zope.interface import Interface, implements

class IReader(Interface):
pass

class IWriter(Interface):
pass

class RootResource(object):
implements(IReader, IWriter)

def root_factory(request):
return RootResource()

def read(context, request):
return Response("""

""")

def write(context, request):
return Response("WRITE! (going to fail)")

if __name__ == '__main__':
config = Configurator(
root_factory=root_factory,
)
config.add_view(read, context=IReader, request_method="GET")
config.add_view(write, context=IWriter, request_method="POST")
app = config.make_wsgi_app()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()

- in this application, a GET request succeds, but POST request results in a "predicate mismatch" error. However, if we swap the order of interface declarations:

class RootResource(object):
implements(IWriter, IReader)

- then the GET request will fail and the POST request will succeed.

I'm finding that the behaviour is the same for any other predicates specified in combination with context=ISomeInterface