Re: [Repoze-dev] Handling webob.exc.HTTPException in router.
We worked this out on IRC. Conclusion: the patch is just about right. We decided to make the following tweaks: - Allow route-specific exception views. - Don't use ZCML to register the default exception views (instead, do that in Configurator.setup_registry). - No new ZCML directives of configurator APIs are necessary, but we need to make set_notfound_view and set_forbidden_view continue to work. - C On 4/1/10 9:29 AM, Andrey Popp wrote: Sorry, I forgot to attach patch. On Thu, Apr 1, 2010 at 5:28 PM, Andrey Popp8may...@gmail.com wrote: Hello, I have a preview for exception views functionality. I've refactored Router to handle exceptions via IView lookups on IRequest, Exception class. That means all exception views should be global (not belongs to specific route) and exception views can be clashed with ordinary views. Forbidden and NotFound views are special case of exception views now. Default views for that exceptions are registered via repoze.bfg.includes/configure.zcml. All tests are pass, 5 tests cases was removed and 7 new was added. If you like it, I will make other changes related to exception views configuration (possibly add methods to Configurator API and new ZCML directive?). Thanks. On Fri, Mar 12, 2010 at 5:27 AM, Chris McDonoughchr...@plope.com wrote: On 3/10/10 9:59 AM, Andrey Popp wrote: The context of such an exception view will be the exception instance itself. If you want a particular exception to be able to use a real context, you'll make it available as an attribute of the exception for use by the registered exception view (e.g. context.context or so). Thanks, this is that I was talking about. Will try to implement. Great. This would be an excellent feature to have. -- Chris McDonough Agendaless Consulting, Fredericksburg VA The repoze.bfg Web Application Framework Book: http://bfg.repoze.org/book -- Andrey Popp phone: +7 911 740 24 91 e-mail: 8may...@gmail.com -- Chris McDonough Agendaless Consulting, Fredericksburg VA The repoze.bfg Web Application Framework Book: http://bfg.repoze.org/book ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev
Re: [Repoze-dev] Handling webob.exc.HTTPException in router.
On 3/10/10 9:07 AM, Andrey Popp wrote: I was thinking of this too — it is good to return control back to application during handling of this kind of errors (4xx). Also it will convert notfound/forbidden views from special cases of Router processing cycle to special cases of exception view. Right, I think it makes sense... do you think you might want to take a stab at implementing that? Ok, what about reusing the current view registering/lookup machinery? I mean can we treat exception views as views for context defined by raised exception? So raising exception is just context switching inside request processing. Pros: * We can define different exception views for different request predicates. * Unification with view machinery. Cons: * We cannot access previously located context (if there was one), cause it replaced with current exception context. * We should register exception views for exception interfaces, not classes. This is because adapter lookup uses IRO, not standard MRO. I think it should probably work like this: - app developers should register views that match with a context that equals the exception class itself, the default request type, and the empty string as a view name. - when bfg encounters any exception when calling a view (or trying to resolve a root factory, etc.. basically the scope handled currently when it catches NotFound/Forbidden), it will do this: exc_view = registry.adapters.lookup((req_iface, providedBy(exc)), IView, name='') if exc_view is not None: response = exc_view(exc, request) The context of such an exception view will be the exception instance itself. If you want a particular exception to be able to use a real context, you'll make it available as an attribute of the exception for use by the registered exception view (e.g. context.context or so). -- Chris McDonough Agendaless Consulting, Fredericksburg VA The repoze.bfg Web Application Framework Book: http://bfg.repoze.org/book ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev
Re: [Repoze-dev] Handling webob.exc.HTTPException in router.
On 3/10/10 9:54 AM, Chris McDonough wrote: The context of such an exception view will be the exception instance itself. If you want a particular exception to be able to use a real context, you'll make it available as an attribute of the exception for use by the registered exception view (e.g. context.context or so). (Note also that, if it has been found, the real context is also available as request.context). - C -- Chris McDonough Agendaless Consulting, Fredericksburg VA The repoze.bfg Web Application Framework Book: http://bfg.repoze.org/book ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev
Re: [Repoze-dev] Handling webob.exc.HTTPException in router.
- app developers should register views that match with a context that equals the exception class itself, the default request type, and the empty string as a view name. - when bfg encounters any exception when calling a view (or trying to resolve a root factory, etc.. basically the scope handled currently when it catches NotFound/Forbidden), it will do this: exc_view = registry.adapters.lookup((req_iface, providedBy(exc)), IView, name='') if exc_view is not None: response = exc_view(exc, request) The context of such an exception view will be the exception instance itself. If you want a particular exception to be able to use a real context, you'll make it available as an attribute of the exception for use by the registered exception view (e.g. context.context or so). Thanks, this is that I was talking about. Will try to implement. -- Andrey Popp phone: +7 911 740 24 91 e-mail: 8may...@gmail.com ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev
Re: [Repoze-dev] Handling webob.exc.HTTPException in router.
But features are *the enemy* of frameworks, so as the author I feel compelled to provide a counterargument even if I don't really believe strongly in it. ;-) I like that repoze.bfg reuses webob for WSGI layer, but why not to reuse exceptions from that package? It is not about features, it is more about extending view API to allow raise exceptions from webob.exc (not all probably, but which are inherited from webob.exc.HTTPClientError). This is like view-lookup can raise NotFound and repoze.bfg.security — Forbidden. In that spirit I'll note these things: - you could use a decorator for the same purpose instead of relying on the framework to do it for you. It would be a pretty stupid decorator, but it would work. I don't think it'll be stupid because it needs to catch HTTPException at initialzation, store it, when augment __call__ method and if the later was raised, it should reraise it during __call__ call. - you could insert the webob.exc.HTTPExceptionMiddleware middleware into your WSGI pipeline; this indeed converts webob exceptions to responses. This is another way of extending the framework. It seems to be more better way than decorating each view, but it does not work, because there will be no INewResponse event fired and so on, even repoze.bfg.exceptions.NotFound and webob.exc.HTTPNotFound will not be semantically equal. That is not a good thing. Thanks. ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev
Re: [Repoze-dev] Handling webob.exc.HTTPException in router.
On 3/8/10 7:41 AM, Andrey Popp wrote: But features are *the enemy* of frameworks, so as the author I feel compelled to provide a counterargument even if I don't really believe strongly in it. ;-) I like that repoze.bfg reuses webob for WSGI layer, but why not to reuse exceptions from that package? It is not about features, it is more about extending view API to allow raise exceptions from webob.exc (not all probably, but which are inherited from webob.exc.HTTPClientError). This is like view-lookup can raise NotFound and repoze.bfg.security — Forbidden. I understand the purpose and the argument already. I'm just saying that there are existing options that don't require it. In that spirit I'll note these things: - you could use a decorator for the same purpose instead of relying on the framework to do it for you. It would be a pretty stupid decorator, but it would work. I don't think it'll be stupid because it needs to catch HTTPException at initialzation, store it, when augment __call__ method and if the later was raised, it should reraise it during __call__ call. - you could insert the webob.exc.HTTPExceptionMiddleware middleware into your WSGI pipeline; this indeed converts webob exceptions to responses. This is another way of extending the framework. It seems to be more better way than decorating each view, but it does not work, because there will be no INewResponse event fired and so on, INewResponse is almost useless, I should have never added it, but I can't remove it now (feature-fear isn't always irrational!). Middleware should almost always be used instead. See the apologetic sidebar in http://docs.repoze.org/bfg/1.2/api/events.html#repoze.bfg.events.NewResponse . The idea that we'd use the existence of this misfeature as a rationale to add more features is not good. even repoze.bfg.exceptions.NotFound and webob.exc.HTTPNotFound will not be semantically equal. That is not a good thing. The fact that these two exceptions are named similarly doesn't necessarily mean they should be handled the same. If someone is currently using webob.exc.HTTPExceptionMiddleware, they are depending on the exception bubbling up. In particular, if we do catch webob.exc.HTTPNotFound in the same exception handler currently serviced by r.b.exceptions.NotFound, it will mean: - a behavior change that may break folks who already rely on middleware to convert webob exceptions to responses. - an invitation to convert other webob exceptions into responses within the router. For instance, if we went purely by name similarlty, HTTPForbidden would then logically need to be caught by the current Forbidden exception handler. Then we'd need to start to argue about whether HTTPUnauthorized should map to the Forbidden exception handler, and so on. - we'd open up the door to asking for other special purpose exception views. We might be asked to add other special case exception handlers and exception views based on WebOb's various exceptions; I could see someone asking for a 500 view when any 500-series webob exception was caught. It just becomes a bit of a rabbit hole. The rabbit hole is avoided entirely if the we document that people should just put the webob.exc.HTTPExceptionMiddleware middleware into their WSGI pipeline if they want WebOb exceptions to be converted to responses. OTOH, it'd be reasonable to provide a generic exception view facility like Zope's where users can map any exception type to a particular view; this is definitely less adhoc and requires less documentation. I'd be +1 on such a feature, I think. At least without thinking about it really hard at the moment. ;-) - C ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev
Re: [Repoze-dev] Handling webob.exc.HTTPException in router.
On 3/8/10 5:23 PM, Andrey Popp wrote: - a behavior change that may break folks who already rely on middleware to convert webob exceptions to responses. It is reasonable -1 for my proposal. FTR, bw compat is about the weakest argument, I think. Backwards compatibility can always be sacrificed as long as the docs spell out how to fix things for upgraders. It just becomes a bit of a rabbit hole. The rabbit hole is avoided entirely if the we document that people should just put the webob.exc.HTTPExceptionMiddleware middleware into their WSGI pipeline if they want WebOb exceptions to be converted to responses. Yes, it would be great, cause I did not know about existence of that middleware before start of our discussion. I'll try to add it somewhere in the docs, or at least somewhere in http://bfg.repoze.org/tutorialbin. By the way, have you tried it? It looks like it should work... OTOH, it'd be reasonable to provide a generic exception view facility like Zope's where users can map any exception type to a particular view; this is definitely less adhoc and requires less documentation. I'd be +1 on such a feature, I think. At least without thinking about it really hard at the moment. ;-) I was thinking of this too — it is good to return control back to application during handling of this kind of errors (4xx). Also it will convert notfound/forbidden views from special cases of Router processing cycle to special cases of exception view. Right, I think it makes sense... do you think you might want to take a stab at implementing that? -- Chris McDonough Agendaless Consulting, Fredericksburg VA The repoze.bfg Web Application Framework Book: http://bfg.repoze.org/book ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev
Re: [Repoze-dev] Handling webob.exc.HTTPException in router.
On 3/7/10 6:46 PM, Andrey Popp wrote: I have ideological question -- why not to handle webob.exc.HTTPException in router? I think it is very useful, consider for example the following case: I need to define some views that works with JSON encoded request body, so there is base class for them: class JSONView(object): def __init__(self, context, request): try: request.json = json.loads(request.body) except ValueError: raise webob.exc.HTTPBadRequest() self.request = request So webob.exc.HTTPBadRequest will be propagated up to Router. I don't have a 100% reasonable answer. It's a bit of a grey area. The most reasonable answer is that this *does* work: class JSONView(object): def __init__(self, context, request): try: request.json = json.loads(request.body) except ValueError: return webob.exc.HTTPBadRequest() self.request = request Instances of exceptions in webob.exc are themselves responses, so they can be returned from a view function. I can see the attraction in making the router able to handle a WebOb exception that implies a response. Given that returning the exception instance does the same thing, it was just easier to document one way (e.g. in http://docs.repoze.org/bfg/1.2/narr/views.html#using-a-view-callable-to-do-a-http-redirect). - C ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev
Re: [Repoze-dev] Handling webob.exc.HTTPException in router.
On 3/7/10 7:36 PM, Andrey Popp wrote: Yes, I know I can make it work by returning webob.exc.HTTPException objects as response. But the point was to decode JSON request at view initialization phase and raise webob.exc.HTTPBadRequest if needed, so in subclasses at request processing phase (__call__ method) I always will have well-formed request objects. That makes sense. If I weren't the author of the framework, and someone suggested that converting WebOb exceptions to responses shouldn't be a feature of the framework, I'd think they were being pretty silly. But features are *the enemy* of frameworks, so as the author I feel compelled to provide a counterargument even if I don't really believe strongly in it. ;-) Apologies in advance. In that spirit I'll note these things: - you could use a decorator for the same purpose instead of relying on the framework to do it for you. It would be a pretty stupid decorator, but it would work. - you could insert the webob.exc.HTTPExceptionMiddleware middleware into your WSGI pipeline; this indeed converts webob exceptions to responses. This is another way of extending the framework. By looking at the Router code it seems that handling repoze.bfg.exceptions.NotFound/Forbidden is some kind of bonus feature for views, because it is more intended for serving repoze.bfg.security and context finding/view lookup mechanisms, isn't it? Originally they were only intended to be raised within views, but we changed things around so they can be raised within root factories and so on. - C ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev