OK, this time it works, and for bonus points it correctly returns 200
OK for the OPTIONS method:
>>> app._gen_request('DELETE', '/releases', status=405)
<Response 405 Method Not Allowed '405 Method Not Allow'>
>>> app._gen_request('DELETE', '/releases', status=405).headers[1]
('Allow', 'GET, POST')
>>> app._gen_request('OPTIONS', '/releases', status=200)
<Response 200 OK '200 OK\n\n\n\n '>
>>> app._gen_request('OPTIONS', '/releases', status=200).headers[1]
('Allow', 'GET, POST')
Doing this in Routes turned out to be harder than expected, and in any
case it would have required coordinated changes across Pylons &/or
apps too. Instead I overrode dispatch() in my PylonsApp (subclassed
from the default pylons.wsgiapp.PylonsApp) in my app's config/
middleware.py as shown in the diffs below.
My routes are always explicit about methods (quite painlessly, as
recently described), I don't need pylons.decorators.rest now, and the
annoying duplication is removed.
Enjoy,
Mike
-from pylons.wsgiapp import PylonsApp
+from pylons.wsgiapp import PylonsApp as _PylonsApp
+from webob.exc import HTTPMethodNotAllowed, HTTPNotFound, HTTPOk
then:
methods = ['GET', 'PUT', 'POST', 'DELETE']
class PylonsApp(_PylonsApp):
def dispatch(self, controller, environ, start_response):
if not controller:
try:
old_method = environ['REQUEST_METHOD']
allowed_methods=[]
mapper = config['routes.map']
for method in methods:
environ['REQUEST_METHOD'] = method
if mapper.match(environ['PATH_INFO']):
allowed_methods.append(method)
if allowed_methods:
exc = HTTPOk() if old_method =='OPTIONS' else
HTTPMethodNotAllowed()
exc.allow = allowed_methods
return exc(environ, start_response)
finally:
environ['REQUEST_METHOD'] = old_method
return HTTPNotFound()(environ, start_response)
else:
return _PylonsApp.dispatch(self, controller, environ,
start_response)
On Dec 15, 8:11 pm, "Mike Burrows (asplake)" <[email protected]>
wrote:
> Hi Shailesh,
>
> Yes I'm aware of (and use) the rest decorators. I kinda like though
> the simplification of having all routing in one place, and (although
> this is perhaps a more personal thing) having a good source of meta
> data describing the application - it seems a pity to me to hide all
> this information inside decorators that provide no protocol for
> extracting it again.
>
> Your solution is succinct and as nice as any I've seen but it's still
> not completely DRY - you need to remember to maintain the dispatcher
> and the allowed list together. An improved decorator could fix that
> for you though I guess. Picky I know, but there's competition for
> frameworks out there and these things frustrate me!
>
> Regards,
> Mike
>
> On Dec 15, 8:44 pm, Shailesh Kochhar <[email protected]> wrote:
>
> > Mike,
>
> > I do something like this in my controllers:
>
> > import pylons.decorators.rest as rest
> > from app.lib.errors import MethodNotAllowedError
>
> > class QuestionController(BaseController):
>
> > �[email protected]_on(GET='get_questions', POST='add_questions')
> > def questions(self, id):
> > raise MethodNotAllowedError(method=request.method, allowed=["GET",
> > "POST"])
>
> > MethodNotAllowedError is an exception class I wrote which serializes to a
> > 405 error.
>
> > - Shailesh
>
> > Mike Burrows (asplake) wrote:
> > > Apologies - I was too hasty. I was fooled into thinking that 405's
> > > were being generated but all I was seeing was the logging of
> > > exceptions. A full solution needs a change somewhere in the
> > > middleware stack I guess. We can pretend I never posted but please
> > > reply if you would like to me to pursue this further!
>
> > > On Dec 15, 9:19 am, "Mike Burrows (asplake)" <[email protected]>
> > > wrote:
> > >> I should add that you use this only on the last route for any given
> > >> path, or you'll never reach the later ones!
>
> > >> Mike
>
> > >> On Dec 15, 9:13 am, "Mike Burrows (asplake)" <[email protected]>
> > >> wrote:
>
> > >>> This is a followup to an issue raised off topic in the thread "Generic
> > >>> routes for API
> > >>> functions"http://groups.google.com/group/pylons-discuss/browse_thread/thread/34...
> > >>> .
> > >>> I said there that I didn't like that a 404 is raised if routes match
> > >>> on path but not on HTTP method. I have since found a solution though,
> > >>> and it's simple enough:
> > >>> from pylons.controllers.util import abort
> > >>> def method_condition(method):
> > >>> # A condition function capable of generating status codes
> > >>> def check_method(environ, result):
> > >>> if environ and 'REQUEST_METHOD' in environ and \
> > >>> environ['REQUEST_METHOD'] not in method:
> > >>> abort(405)
> > >>> else:
> > >>> return True
> > >>> return check_method
> > >>> Use with
> > >>> conditions={'function': method_condition(method)}
> > >>> on your route. I have a helper that generates either this form or the
> > >>> simpler
> > >>> conditions={'method': method}
> > >>> form depending on the presence of a status code, but I didn't want to
> > >>> obscure the solution unecessarily.
> > >>> Enjoy,
> > >>> Mike
> > >>> [email protected]http://positiveincline.comhttp://twitter.com/asplake
>
> > > --
>
> > > You received this message because you are subscribed to the Google Groups
> > > "pylons-discuss" group.
> > > To post to this group, send email to [email protected].
> > > To unsubscribe from this group, send email to
> > > [email protected].
> > > For more options, visit this group
> > > athttp://groups.google.com/group/pylons-discuss?hl=en.
--
You received this message because you are subscribed to the Google Groups
"pylons-discuss" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/pylons-discuss?hl=en.