mailRe: r2533 - in /1.2: errors.py prompt/interpreter.py relax


Others Months | Index by Date | Thread Index
>>   [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Header


Content

Posted by Chris MacRaild on August 11, 2006 - 17:50:
On Thu, 2006-08-10 at 12:27 +0100, Chris MacRaild wrote:
On Thu, 2006-08-10 at 20:51 +1000, Edward d'Auvergne wrote:
Thanks.  I have a suggestion to simplify the state saving code and
that is that the save_state function is called within the BaseError
class.  This means that save_state is only called from one place in
the code by placing it within the __str__ function (which is called
to
get the error message).  For example something like:

    class BaseError(Exception):
        def __str__(self):
            # Save the program state.
            if Debug:
                self.save_state()

            # The RelaxError message.
            return ("RelaxError: " + self.text + "\n")

There are a couple of reasons I didn't do it this way. One is that
__str__ is a 'special' function as far as Python is concerned, and it
exists for a specific purpose (same with all the double-underscore
functions). Although it's difficult to imagine how it might cause
problems in this case, I'm inclined to avoid messing with it on
principle. The second reason is that the way I've implimented it now
gives us greater control - perhaps there will be a set of Errors that
we
dont want to save state. Or, as I've done with RelaxFault, we might
want
to save state in all cases, not just if Debug (the logic here being
that
RelaxFault always reflects a bug, and we want all the info we can
about
it especially if it is difficult to reproduce). I appreciate that the
if
Debug: self.save_state() gets repeditive, but I think its a price
worth
paying in this case. 

I've been thinking some more about this, and wonder if there is a better
way of doing it. The problem is that Python exceptions are generally
pretty minimalist constructions, and it seems hard to avoid very crude
hacks when getting them to do anything more sophisticated. It seems that
this is historical - in early versions of Python, there was no special
Exception class, and raise could act on any object. This is still the
case, though it's deprecated, so there is nothing the Exception itself
can do to change the way raise handles it. The way around it is to do
the appropriate handling tasks in the program code itself. The sort of
thing I'm thinking about would have:

class BaseError(Exception):
    # -1 => never, 0 => if Debug, 1 => always
    save_state = 0
    def __str__(self):
        return ("RelaxError: " + self.text + "\n")

class RelaxFault(BaseError):
    save_state = 1
    def __init__(self):
        ...

Then in the main program script, around line 151 (in the if mode ==
'prompt' or mode == 'script' block) we would have:

try:
    self.interpreter.run()
except BaseError:
    err = sys.exc_info()
    exception = err[1]
    if exception.save_state == 1
        state.save()
    elif exception.save_state == 0
        if Debug:
            self.interpreter._State.save()
    del err, exception
    raise

The logic here is that BaseError simply defines a flag indicating the
default behaviour, and subclasses can override this as appropriate. Then
we use the more normal exception handling machinery to ensure that the
behaviour occurs, rather than coding that into the exception itself.
This gives us even more flexibility, because we might want (around line
180):

# Run the tests.
elif mode == 'test suite':
    try:
        Test_suite(self)
    except BaseError:
        err = sys.exc_info()
        exception = err[1]
        if exception.save_state >= 0
            self.interpreter._State.save()
        del err, exception
        raise

Here exceptions will cause a state.save(), irrespective of Debug status,
because we will always want to know about about errors during testing.

The other advantage of this approach is that the state.save() only
happens if the exception has propagated all the way to the top of the
stack. With the save_state() function in __init__(), the state is saved
when the exception class is instantiated ie. when it is raised, even if
it is subsequently caught and dealt with.

Chris




Related Messages


Powered by MHonArc, Updated Fri Aug 11 19:20:14 2006