# Path: selene/core/exceptions.py
# class TimeoutException(AssertionError):
#     def __init__(self, msg=None):
#         self.msg = msg
# 
#     def __str__(self):
#         exception_msg = "Message: %s\n" % self.msg
#         return exception_msg
# 
# Path: selene/common/fp.py
# def identity(it: T) -> T:
#     return it


import time
from abc import abstractmethod, ABC
from typing import Generic, Callable, TypeVar, Optional
from selene.core.exceptions import TimeoutException
from selene.common.fp import identity

    # todo: consider renaming to `def to(...)`, though will sound awkward when wait.to(condition)
    def for_(self, 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'''

Timed out after {timeout}s, while waiting for:
{entity}.{fn}

Reason: {reason_string}'''
                    )


# Path: selene/core/exceptions.py
# class TimeoutException(AssertionError):
#     def __init__(self, msg=None):
#         self.msg = msg
# 
#     def __str__(self):
#         exception_msg = "Message: %s\n" % self.msg
#         return exception_msg
# 
# Path: selene/common/fp.py
# def identity(it: T) -> T:
#     return it


# Path: selene/core/wait.py
import time
from abc import abstractmethod, ABC
from typing import Generic, Callable, TypeVar, Optional
from selene.core.exceptions import TimeoutException
from selene.common.fp import identity


    # todo: consider renaming to `def to(...)`, though will sound awkward when wait.to(condition)
    def for_(self, 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'''

Timed out after {timeout}s, while waiting for:
{entity}.{fn}

Reason: {reason_string}'''
                    )


                    raise self._hook_failure(failure)