Pylons/pyramid — pull request #1480 by hugobranquinho (2014-12-04 16:19:24+00:00)
Title: Predicate error with custom HTTP Error

The reason for this change happen when i wanted to customize my errors messages, layout and http status codes on a REST JSON application.
I looked for a way to do this without changing the pyramid code, but i can't find it, but if it is please tell me :)

Here's a example of what i'm trying to do.

@view_defaults(route_name='test', renderer='json')
class Test(object):
def __init__(self, request):
self.request = request

@view_config(request_method='POST')
def post(self):
return 'POST'

@view_config(request_method='GET')
def get(self):
return 'GET'

If we call this view with `PUT` method for example, we get 404, and that is not technically true, i think the 405 it's the correct one.

To change this i make the predicates validations a little more flexible.
Instead of validating if is the predicate is `True` or `False` and raise 404, we validate if is `True` or `False` and if is a `PredicateMismatch` exception. If we get a exception we raise that exception, if `False` we give the default, 404.

Now we have another problem.

class PredicateMismatchForbidden(HTTPForbidden, PredicateMismatch):
pass

class IPAddressPredicate(object):
def __init__(self, val, config):
self.val = val
def text(self):
return "ip_address = %s" % self.val
phash = text
def __call__(self, context, request):
if request.remote_addr == self.val:
return True
else:
raise PredicateMismatchForbidden()

@view_defaults(route_name='test', renderer='json')
class Test(object):
def __init__(self, request):
self.request = request

@view_config(request_method='POST')
def post(self):
return 'POST'

@view_config(request_method='GET', ip_address='1.1.1.1')
def get(self):
return 'GET'

If we call this view with `GET` method and with IP '9.9.9.9', we get 405, but we want a 403 raised by invalid IP, because we sent `GET` and that match with the method `Test.get`.
So the solution has to define the valide predicates on the error to create some kind of priority.

This is a small sugestion. I think this need more changes, like defining `PredicateMismatch` as `HTTPError` and create all HTTPErrors for `PredicateMismatch`.
I tried to change only the necessary to keep the code work the same way, and if you agree we can make a better change on this.

Thanks and sorry for my english :)