Welcome, guest | Sign In | My Account | Store | Cart

Calling the "forward" method transfers processing to a new screen. It never returns. This code is taken from multiple places, so I haven't bothered to keep the classes intact, I've just taken the meat. More generally, this is an example of state machine with a main loop. At any point, you can say, "I'm ready to change state. Do it. Go back to the loop. Don't return--just throw away my current stack."

Python, 113 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
"""Forward processing to a new screen."""

__docformat__ = "restructuredtext"


def forward(self, screen, *args, **kargs):
    """Forward processing to a new screen.  This method does not return.

    Generate a ``Forward`` exception which
    aquarium.util.Aquarium.screenLoop_ class is prepared to catch.

    screen
      This is the module name of the screen relative to the screen
      directory.

    ``*args``, ``**kargs``
      The arguments to pass to the screen's ``__call__`` method.

    .. _aquarium.util.Aquarium.screenLoop: 
        aquarium.util.Aquarium.Aquarium-class.html#screenLoop

    """
    raise Forward(screen, *args, **kargs)


class Forward(Exception):
    
    """Raise an instance of this class to make Aquarium do a forward.

    Actually, you should use aquarium.util.InternalLibrary.forward_ to do that
    for you.

    The following attributes are used:

    screen
      The module name of the screen relative to the ``screen`` directory
    ``*args``, ``**kargs``
      The arguments to pass to the screen's ``__call__`` method.

    .. _aquarium.util.InternalLibrary.forward: 
       aquarium.util.InternalLibrary.InternalLibrary-class.html#forward

    """

    def __init__(self, screen, *args, **kargs):
        """Just accept the parameters."""
        Exception.__init__(self)
        self.screen = screen
        self.args = args
        self.kargs = kargs


def screenLoop(self):
    """Show the desired screen, and loop around to handle exceptions.

    By using a loop, the same code path can be used for exceptions.  In 
    fact:

    * The aquarium.util.InternalLibrary.Forward_ exception results in 
      looping around to show the desired screen to forward to.

    * ``ImportError``'s and ``AttributeError``'s while trying to import the
      screen result in the ``not_found`` screen.

    * Any other ``Exception`` results in the ``exception`` screen.
    
    Be especially wary of infinite loops since we're catching all
    exceptions and looping around.  Use ``handleDoubleException`` in these
    cases, but note that it too will raise an exception, by design.

    If a screen runs successfully to completion, call
    ``self._ctx.dba.commit()`` and return whatever the screen returns.

    .. _aquarium.util.InternalLibrary.Forward: 
       aquarium.util.InternalLibrary.Forward-class.html

    """
    from InternalLibrary import Forward
    class _Continue(Exception): pass    # Can't use continue in an except.
    MAX_FORWARDS = 1024
    ctx = self._ctx
    if hasattr(ctx, "screen"):          # We had an exception in initAll.
        screen, args, kargs = ctx.screen, ctx.args, ctx.kargs
    else:
        screen, args, kargs = ctx.url.whichScreen(), (), {}
    self._prevExc, self._prevExcInfo = None, None
    if not screen:
        screen = properties.DEFAULT_SCREEN
    if not ctx.iLib.validModuleName(screen):
        screen, args, kargs = "not_found", (screen,), {}
    for _ignored in xrange(MAX_FORWARDS):
        try:
            ctx.screen = screen
            try:
                ctx.screenInstance = ctx.iLib.aquariumFactory(
                    "screen." + screen)
            except (ImportError, AttributeError), e:
                self.catchDoubleException(e)
                screen, args, kargs = "not_found", (e), {}
                raise _Continue
            buf = ctx.iLib.inverseExtend(ctx.screenInstance.__call__, 
                                         *args, **kargs)
            if properties.USE_DATABASE: 
                ctx.dba.commit()
            return buf
        except _Continue:
            pass
        except Forward, e:
            screen, args, kargs = e.screen, e.args, e.kargs
        except Exception, e:
            self.catchDoubleException(e)
            screen, args, kargs = "exception", (exc_info(),), {}
    raise OverflowError("Too many forwards")

Note that this comes from the Aquarium Web application framework, but any references to Aquarium can easily be removed.