On Mon, May 20, 2013 at 9:56 PM, Shannon Cruey
<shannon.cr...@cloudsidekick.com> wrote:
> No, it's the opposite.  If the processor code catches and handles the
> exception, it would still not raise it back up to my main app, even if it
> did move on to the next processor.

But if one of your custom application processors handles custom
exceptions to take specific actions, then there won't be any reason to
propagate the exceptions up to the application (I adapted the code you
posted previously):

        def custom_processor(handler):
            try:
                return handler()
            except InfoException as ex:
                # I use a custom HTTP status code to indicate
'information' back to the user.
                web.ctx.status = "280 Informational Response"
                logger.exception(ex.__str__())
                return ex.__str__()
            except SessionError as ex:
                logger.exception(ex.__str__())
                # now, all our ajax calls are from jQuery, which sets
a header - X-Requested-With
                # so if we have that header, it's ajax, otherwise we
can redirect to the login page.
                # a session error means we kill the session
                session.kill()
                if web.ctx.env.get("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest":
                    web.ctx.status = "480 Session Error"
                    return ex.__str__()
                else:
                    logger.debug("Standard Request - redirecting to
the login page...")
                    raise web.seeother('/static/login.html')
            except Exception as ex:
                # web.ctx.env.get('HTTP_X_REQUESTED_WITH')
                web.ctx.status = "400 Bad Request"
                logger.exception(ex.__str__())
                return ex.__str__()



>
> If handle_with_processors didn't have any try block at all, then any
> exceptions would be raised to the calling app.  For my use case that's fine
> but I suspect for a great many simpler use cases it might be annoying to
> require the user to write exception handler.

If users don't use exceptions as flow control mechanism, then I expect
they won't need to catch real *exceptions* (unless they want to log a
message):  an internal error sent back to the client should be enough.

However I think here we have two problems:  the first is to handle
application exceptions, the second is logging a message when an
exception is caught by the application.  The former could be easily
solved using application processors, while I think the latter is
harder to fix because the framework actually lacks of a common logging
interface.

>
> I certainly don't mind overloading.
>
> One compromise solution might be to extend handle_with_processors with an
> optional argument of whether or not to trap errors, set default to True.
> But, that doesn't seem very pythonic.
>
> I'm happy enough with what I've had to do, and will leave it up to better
> experts than me to determine how (or even if) this should result in an
> enhancement.
>
> Peace... NSC
>
>
> On Mon, May 20, 2013 at 2:13 PM, Matteo Landi <mat...@matteolandi.net>
> wrote:
>>
>> On Mon, May 20, 2013 at 7:11 PM, Shannon Cruey
>> <shannon.cr...@cloudsidekick.com> wrote:
>> > I fiddled with that a lot to get it right, so my memory of the process
>> > is a
>> > little hazy.  Give it a try!
>> >
>>
>> I will.
>>
>> > My issue was that I needed handle_with_processors to *not* catch the
>> > exceptions at all - because I wanted to do my own error handling
>> > end-to-end
>> > by actually returning specific exception types and handling them.
>> > Handle_with_processors was hijacking the exceptions.
>> >
>>
>> If application processors were allowed to catch exceptions, would you
>> still be in need of subclassing web.Application?  Probably not, you
>> could simply chain a custom processor with a custom try-catch and
>> everything should work like a charm. (Please, correct me if I am
>> wrong)
>>
>>
>> Matteo
>>
>> > I'd suggest the best case for usability would be that
>> > handle_with_processors
>> > not have a try block, and leave it up to a higher level wrapper to
>> > handle
>> > them appropriately.  However, I didn't dig deep enough into web.py to
>> > see if
>> > there's a reason it's done like that, and my overload is working just
>> > fine.
>> >
>> >
>> > On Mon, May 20, 2013 at 12:50 PM, Matteo Landi <mat...@matteolandi.net>
>> > wrote:
>> >>
>> >> On Sun, May 19, 2013 at 6:19 PM, Shannon Cruey
>> >> <shannon.cr...@cloudsidekick.com> wrote:
>> >> > The problem is the processor function in the application.py module
>> >> > has a
>> >> > try
>> >> > block in it, so it's redirecting to the internal error handler.  I
>> >> > have
>> >>
>> >> I am looking at the code of the method ``handle_with_processors`` of
>> >> the application module:  am I wrong saying that the try-catch block
>> >> could be safely moved out of the ``process`` function and put around
>> >> the line containing ``return process(self.processors)``?  This way
>> >> processors will be able to handle certain kind of exceptions and still
>> >> propagate unhandled ones to the framework (to enable default exception
>> >> management).
>> >>
>> >> What do you think about that?  If you don't see any issue I can
>> >> provide a pull request with these changes.
>> >>
>> >>
>> >> Regards,
>> >>
>> >> Matteo
>> >>
>> >> > successfully overloaded this function in my main module and am able
>> >> > to
>> >> > return different status codes as I like.  Here's what I did in my
>> >> > main
>> >> > code:
>> >> >  (You can see the entire file at
>> >> >
>> >> >     app = ExceptionHandlingApplication(urls, globals(),
>> >> > autoreload=True)
>> >> >
>> >> >
>> >> > Then here's that class:
>> >> >
>> >> > class ExceptionHandlingApplication(web.application):
>> >> >
>> >> >     """
>> >> >
>> >> >     This is an overload of the standard web.application class.
>> >> >
>> >> >     Main reason? In application.py, the 'handle_with_processors'
>> >> > function
>> >> >
>> >> >         converts *any* exception into the generic web.py
>> >> > _InternalError.
>> >> >
>> >> >
>> >> >
>> >> >     This interferes, because we wanna trap the original error an make
>> >> > determinations
>> >> >
>> >> >         on how to reply to the client.
>> >> >
>> >> >
>> >> >
>> >> >     So, we overloaded the function and fixed the error handing.
>> >> >
>> >> >     """
>> >> >
>> >> >     def handle_with_processors(self):
>> >> >
>> >> >         def process(processors):
>> >> >
>> >> >             try:
>> >> >
>> >> >                 if processors:
>> >> >
>> >> >                     p, processors = processors[0], processors[1:]
>> >> >
>> >> >                     return p(lambda: process(processors))
>> >> >
>> >> >                 else:
>> >> >
>> >> >                     return self.handle()
>> >> >
>> >> >             except (web.HTTPError, KeyboardInterrupt, SystemExit):
>> >> >
>> >> >                 raise
>> >> >
>> >> >             except InfoException as ex:
>> >> >
>> >> >                 # I use a custom HTTP status code to indicate
>> >> > 'information'
>> >> > back to the user.
>> >> >
>> >> >                 web.ctx.status = "280 Informational Response"
>> >> >
>> >> >                 logger.exception(ex.__str__())
>> >> >
>> >> >                 return ex.__str__()
>> >> >
>> >> >             except SessionError as ex:
>> >> >
>> >> >                 logger.exception(ex.__str__())
>> >> >
>> >> >                 # now, all our ajax calls are from jQuery, which sets
>> >> > a
>> >> > header - X-Requested-With
>> >> >
>> >> >                 # so if we have that header, it's ajax, otherwise we
>> >> > can
>> >> > redirect to the login page.
>> >> >
>> >> >
>> >> >
>> >> >                 # a session error means we kill the session
>> >> >
>> >> >                 session.kill()
>> >> >
>> >> >
>> >> >
>> >> >                 if web.ctx.env.get("HTTP_X_REQUESTED_WITH") ==
>> >> > "XMLHttpRequest":
>> >> >
>> >> >                     web.ctx.status = "480 Session Error"
>> >> >
>> >> >                     return ex.__str__()
>> >> >
>> >> >                 else:
>> >> >
>> >> >                     logger.debug("Standard Request - redirecting to
>> >> > the
>> >> > login page...")
>> >> >
>> >> >                     raise web.seeother('/static/login.html')
>> >> >
>> >> >             except Exception as ex:
>> >> >
>> >> >                 # web.ctx.env.get('HTTP_X_REQUESTED_WITH')
>> >> >
>> >> >                 web.ctx.status = "400 Bad Request"
>> >> >
>> >> >                 logger.exception(ex.__str__())
>> >> >
>> >> >                 return ex.__str__()
>> >> >
>> >> >
>> >> >
>> >> >         return process(self.processors)
>> >> >
>> >> >
>> >> >
>> >> > On Sun, May 19, 2013 at 6:46 AM, Matteo Landi
>> >> > <mat...@matteolandi.net>
>> >> > wrote:
>> >> >>
>> >> >> Hi there,
>> >> >>
>> >> >> What is the best way to manage certain type of exceptions so that
>> >> >> they
>> >> >> don't produce a '500 Internal Error' HTTP status?
>> >> >>
>> >> >> First I thought about request decorators but then I realized that
>> >> >> decorating *each* request seem to be a bit overkill.  Then I thought
>> >> >> about application decorators:  the documentation even contains an
>> >> >> example where a try-except block is put within an handler.  So I
>> >> >> come
>> >> >> up with the following handler:
>> >> >>
>> >> >> def manage_content_exceptions(handler):
>> >> >>     web.ctx.logger.info("before_manage")
>> >> >>     try:
>> >> >>         return handler()
>> >> >>     except app.exceptions.ResponseContent as r:
>> >> >>         return r.content
>> >> >>     finally:
>> >> >>         web.ctx.logger.info("after_manage")
>> >> >>
>> >> >> What happens here is that the finally block is never executed and
>> >> >> consequently the exception is caught by the application and an
>> >> >> internal error is sent back to the client.
>> >> >>
>> >> >> Could you please shed some light on the subject and tell me what's
>> >> >> wrong with my handler?  I even found another discussion [1] about
>> >> >> same
>> >> >> issue but unfortunately it is unanswered.
>> >> >>
>> >> >>
>> >> >> Regards,
>> >> >>
>> >> >> Matteo
>> >> >>
>> >> >> [1] https://groups.google.com/d/msg/webpy/f7IBxCgvIoY/GQxeHKVw8pcJ
>> >> >>
>> >> >> --
>> >> >> You received this message because you are subscribed to the Google
>> >> >> Groups
>> >> >> "web.py" group.
>> >> >> To unsubscribe from this group and stop receiving emails from it,
>> >> >> send
>> >> >> an
>> >> >> email to webpy+unsubscr...@googlegroups.com.
>> >> >> To post to this group, send email to webpy@googlegroups.com.
>> >> >> Visit this group at http://groups.google.com/group/webpy?hl=en.
>> >> >> For more options, visit https://groups.google.com/groups/opt_out.
>> >> >>
>> >> >>
>> >> >
>> >> > --
>> >> > You received this message because you are subscribed to the Google
>> >> > Groups
>> >> > "web.py" group.
>> >> > To unsubscribe from this group and stop receiving emails from it,
>> >> > send
>> >> > an
>> >> > email to webpy+unsubscr...@googlegroups.com.
>> >> > To post to this group, send email to webpy@googlegroups.com.
>> >> > Visit this group at http://groups.google.com/group/webpy?hl=en.
>> >> > For more options, visit https://groups.google.com/groups/opt_out.
>> >> >
>> >> >
>> >>
>> >> --
>> >> You received this message because you are subscribed to the Google
>> >> Groups
>> >> "web.py" group.
>> >> To unsubscribe from this group and stop receiving emails from it, send
>> >> an
>> >> email to webpy+unsubscr...@googlegroups.com.
>> >> To post to this group, send email to webpy@googlegroups.com.
>> >> Visit this group at http://groups.google.com/group/webpy?hl=en.
>> >> For more options, visit https://groups.google.com/groups/opt_out.
>> >>
>> >>
>> >
>> > --
>> > You received this message because you are subscribed to the Google
>> > Groups
>> > "web.py" group.
>> > To unsubscribe from this group and stop receiving emails from it, send
>> > an
>> > email to webpy+unsubscr...@googlegroups.com.
>> > To post to this group, send email to webpy@googlegroups.com.
>> > Visit this group at http://groups.google.com/group/webpy?hl=en.
>> > For more options, visit https://groups.google.com/groups/opt_out.
>> >
>> >
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "web.py" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to webpy+unsubscr...@googlegroups.com.
>> To post to this group, send email to webpy@googlegroups.com.
>> Visit this group at http://groups.google.com/group/webpy?hl=en.
>> For more options, visit https://groups.google.com/groups/opt_out.
>>
>>
>
> --
> You received this message because you are subscribed to the Google Groups
> "web.py" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to webpy+unsubscr...@googlegroups.com.
> To post to this group, send email to webpy@googlegroups.com.
> Visit this group at http://groups.google.com/group/webpy?hl=en.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"web.py" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to webpy+unsubscr...@googlegroups.com.
To post to this group, send email to webpy@googlegroups.com.
Visit this group at http://groups.google.com/group/webpy?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to