Query a slice of the events.

        Events are always returned in the order the were added.

        It also queries older event archives until it finds the event UUIDs
        necessary.

        Parameters:
        from_   -- if not None, return only events added after the event with
                   id `from_`. If None, return from the start of history.
        to      -- if not None, return only events added before, and
                   including, the event with event id `to`. If None, return up
                   to, and including, the last added event.

        returns -- an iterable of (event id, eventdata) tuples.

def get_events(self, from_=None, to=None):
        """Query a slice of the events.

        Events are always returned in the order the were added.

        It also queries older event archives until it finds the event UUIDs
        necessary.

        Parameters:
        from_   -- if not None, return only events added after the event with
                   id `from_`. If None, return from the start of history.
        to      -- if not None, return only events added before, and
                   including, the event with event id `to`. If None, return up
                   to, and including, the last added event.

        returns -- an iterable of (event id, eventdata) tuples.

        """
        if from_:
            frombatchno = self._find_batch_containing_event(from_)
            if frombatchno is None:
                msg = 'from_={0}'.format(from_)
                raise EventStore.EventKeyDoesNotExistError(msg)
        else:
            frombatchno = 0
        if to:
            tobatchno = self._find_batch_containing_event(to)
            if tobatchno is None:
                raise EventStore.EventKeyDoesNotExistError('to={0}'.format(to))
        else:
            tobatchno = self.batchno

        batchno_range = range(frombatchno, tobatchno + 1)
        nbatches = len(batchno_range)
        if nbatches == 1:
            event_ranges = [(from_, to)]
        else:
            event_ranges = itertools.chain([(from_, None)],
                                           itertools.repeat((None, None),
                                                            nbatches - 2),
                                           [(None, to)])
        for batchno, (from_in_batch, to_in_batch) in zip(batchno_range,
                                                         event_ranges):
            estore = self._open_event_store(batchno)
            with contextlib.closing(estore):
                for eventtuple in estore.get_events(from_in_batch,
                                                    to_in_batch):
                    yield eventtuple