Returns the next result. If no result is availble within the specified 
        (during construction) "timeout" then a ``PiperError`` which wraps a  
        ``TimeoutError`` is **returned**.

        If the result is a ``WorkerError`` it is also wrapped in a 
        ``PiperError`` and is returned or raised if "debug" mode was specified 
        at initialization. If the result is a ``PiperError`` it is propagated.

def next(self):
        """
        Returns the next result. If no result is availble within the specified 
        (during construction) "timeout" then a ``PiperError`` which wraps a  
        ``TimeoutError`` is **returned**.

        If the result is a ``WorkerError`` it is also wrapped in a 
        ``PiperError`` and is returned or raised if "debug" mode was specified 
        at initialization. If the result is a ``PiperError`` it is propagated.
        
        """
        try:
            next = self.outbox.next()
        except StopIteration, excp:
            self.log.debug('Piper %s has processed all jobs (finished)' % self)
            self.finished = True
            # We re-raise StopIteration as part of the iterator protocol.
            # And the outbox should do the same.
            raise excp
        except (AttributeError, RuntimeError), excp:
            # probably self.outbox.next() is self.None.next()
            self.log.error('Piper %s has not yet been started.' % self)
            raise PiperError('Piper %s has not yet been started.' % self, excp)
        except IndexError, excp:
            # probably started before connected
            self.log.error('Piper %s has been started before connect.' % self)
            raise PiperError('Piper %s has been started before connect.' % self, excp)
        except TimeoutError, excp:
            self.log.error('Piper %s timed out waited %ss.' % \
                           (self, self.timeout))
            next = PiperError(excp)
            # we do not raise TimeoutErrors so they can be skipped.
        if isinstance(next, WorkerError):
            # return the WorkerError instance returned (not raised) by the
            # worker Process.
            self.log.error('Piper %s generated %s"%s" in func. %s on argument %s' % \
                     (self, type(next[0]), next[0], next[1], next[2]))
            if self.debug:
                # This makes only sense if you are debugging a piper as it will 
                # most probably crash papy and python NuMap worker processes 
                # threads will hang.
                raise PiperError('Piper %s generated %s"%s" in func %s on argument %s' % \
                            (self, type(next[0]), next[0], next[1], next[2]))
            next = PiperError(next)
        elif isinstance(next, PiperError):
            # Worker/PiperErrors are wrapped by workers
            if self.debug:
                raise next
            self.log.debug('Piper %s propagates %s' % (self, next[0]))
        return next