Guard decorator

While still finishing classes for this spring, I managed to sneak in some time to write a short decorator to make my life easier.

Up until this point I have not been using any exception handling at all. If Qt side of the program has some problems, they are automatically taken care of anyway and the main program does not crash. If the main program has some problems, I get an unhandled exception and the program exits.

I did not want to litter the code with exception handling, so I chose to handle them in centralised location: Character class. Lots of the game logic flows through this class eventually anyway. Especially the methods that are used to perform actions (moving, combat, using items) are used very often.

Repeating the same code for these central methods was something that I did not want to do, so I wrote a decorator to take care of the problem:

@decorator
def guarded_action(wrapped_function, *args, **kwargs):
    """
    Function to guard against exceptions in action functions
    """
    try:
        result = wrapped_function(*args, **kwargs)
        return result
    except Exception:
        self = args[0]
        self.tick = 10
        self.raise_event(ErrorEvent(self))

Very simple and straightforward piece of code that calls the decorated function and returns the possible return value. In case of an exception, ErrorEvent is raised after setting tick of the character to 10. This is done in order to give other characters a chance to act too in case there is a single character that is in a broken state. ErrorEvent is standard pyherc-event that gets reported on UI with text “World phases out around you for a second” or “{0} is unsure about existence of world” depending whether the exception was raised during the players or computers turn.

The decorator is used like:

@guarded_action
@logged
def move(self, direction, action_factory):
    """
    Move this character to specified direction

    :param direction: direction to move
    :type direction: integer
    :param action_factory: factory to create actions
    :type action_factory: ActionFactory
    """
    action = action_factory.get_action(MoveParameters(
                                                      self,
                                                      direction,
                                                      'walk'))
    action.execute()

Very clean and unobtrusive. Of course using a decorator like this will incur a performance hit, especially when there are multiple chained ones. Since the game is turn based, I don’t expect this to be a problem.

Code for the change is in commit ba1a80ccaeb7f7196c6c3bdf38a93e10d05fed88

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s