def METHOD_NAME(fn: Callable[[E], R]) -> R:
    finish_time = time.time() + self._timeout
    while True:
        try:
            return fn(self.entity)
        except Exception as reason:
            if time.time() > finish_time:
                reason_message = str(reason)
                reason_string = '{name}: {message}'.format(
                    name=reason.__class__.__name__,
                    message=reason_message,
                )
                # TODO: think on how can we improve logging failures in selene, e.g. reverse msg and stacktrace
                # stacktrace = getattr(reason, 'stacktrace', None)
                timeout = self._timeout
                entity = self.entity
                failure = TimeoutException(
                    f'\n'
                    f'\nTimed out after {timeout}s, while waiting for:'
                    f'\n{entity}.{fn}'
                    f'\n'
                    f'\nReason: {reason_string}'
                )
                raise self._hook_failure(failure)