h2o-py/h2o/utils/progressbar.py
def execute(self, progress_fn, print_verbose_info=None):
        """
        Start the progress bar, and return only when the progress reaches 100%.

        :param progress_fn: the executor function (or a generator). This function should take no arguments
            and return either a single number -- the current progress level, or a tuple (progress level, delay),
            where delay is the time interval for when the progress should be checked again. This function may at
            any point raise the ``StopIteration(message)`` exception, which will interrupt the progress bar,
            display the ``message`` in red font, and then re-raise the exception.
        :raises StopIteration: if the job is interrupted. The reason for interruption is provided in the exception's
            message. The message will say "cancelled" if the job was interrupted by the user by pressing Ctrl+C.
        """
        assert_is_type(progress_fn, FunctionType, GeneratorType, MethodType)
        if isinstance(progress_fn, GeneratorType):
            # Convert generator to a regular function
            progress_fn = (lambda g: lambda: next(g))(progress_fn)

        # Initialize the execution context
        self._next_poll_time = 0
        self._t0 = time.time()
        self._x0 = 0
        self._v0 = 0.01  # corresponds to 100s completion time
        self._ve = 0.01

        progress = 0
        status = None  # Status message in case the job gets interrupted.
        try:
            while True:
                # We attempt to synchronize all helper functions, ensuring that each of them has the same idea
                # for what the current time moment is. Otherwise we could have some corner cases when one method
                # says that something must happen right now, while the other already sees that moment in the past.
                now = time.time()

                # Query the progress level, but only if it's time already
                if self._next_poll_time <= now:
                    res = progress_fn()  # may raise StopIteration
                    assert_is_type(res, (numeric, numeric), numeric)
                    if not isinstance(res, tuple):
                        res = (res, -1)
                    # Progress querying could have taken some time, so update the current time moment
                    now = time.time()
                    self._store_model_progress(res, now)
                    self._recalculate_model_parameters(now)

                # Render the widget regardless of whether it's too early or not
                progress = min(self._compute_progress_at_time(now)[0], 1)
                if progress == 1 and self._get_real_progress() >= 1:
                    # Do not exit until both the model and the actual progress reach 100% mark.
                    break
                result = self._widget.render(progress)
                assert_is_type(result, RenderResult)
                time0 = result.next_time
                time1 = self._get_time_at_progress(result.next_progress)
                next_render_time = min(time0, time1)
                self._draw(result.rendered)

                # Wait until the next rendering/querying cycle
                wait_time = min(next_render_time, self._next_poll_time) - now
                if wait_time > 0:
                    time.sleep(wait_time)
                    if print_verbose_info is not None:
                        print_verbose_info(progress)
        except KeyboardInterrupt:
            # If the user presses Ctrl+C, we interrupt the progress bar.
            status = "cancelled"
        except StopIteration as e:
            # If the generator raises StopIteration before reaching 100%, then the progress display will
            # reamin incomplete.
            status = str(e)

        # Do one final rendering before we exit
        result = self._widget.render(progress=progress, status=status)
        self._draw(result.rendered, final=True)

        if status == "cancelled":
            # Re-raise the exception, to inform the upstream caller that something unexpected happened.
            raise StopIteration(status)
def execute(self, progress_fn, print_verbose_info=None):
        """
        Start the progress bar, and return only when the progress reaches 100%.

        :param progress_fn: the executor function (or a generator). This function should take no arguments
            and return either a single number -- the current progress level, or a tuple (progress level, delay),
            where delay is the time interval for when the progress should be checked again. This function may at
            any point raise the ``StopIteration(message)`` exception, which will interrupt the progress bar,
            display the ``message`` in red font, and then re-raise the exception.
        :raises StopIteration: if the job is interrupted. The reason for interruption is provided in the exception's
            message. The message will say "cancelled" if the job was interrupted by the user by pressing Ctrl+C.
        """
        assert_is_type(progress_fn, FunctionType, GeneratorType, MethodType)
        if isinstance(progress_fn, GeneratorType):
            # Convert generator to a regular function
            progress_fn = (lambda g: lambda: next(g))(progress_fn)

        # Initialize the execution context
        self._next_poll_time = 0
        self._t0 = time.time()
        self._x0 = 0
        self._v0 = 0.01  # corresponds to 100s completion time
        self._ve = 0.01

        progress = 0
        status = None  # Status message in case the job gets interrupted.
        try:
            while True:
                # We attempt to synchronize all helper functions, ensuring that each of them has the same idea
                # for what the current time moment is. Otherwise we could have some corner cases when one method
                # says that something must happen right now, while the other already sees that moment in the past.
                now = time.time()

                # Query the progress level, but only if it's time already
                if self._next_poll_time <= now:
                    res = progress_fn()  # may raise StopIteration
                    assert_is_type(res, (numeric, numeric), numeric)
                    if not isinstance(res, tuple):
                        res = (res, -1)
                    # Progress querying could have taken some time, so update the current time moment
                    now = time.time()
                    self._store_model_progress(res, now)
                    self._recalculate_model_parameters(now)

                # Render the widget regardless of whether it's too early or not
                progress = min(self._compute_progress_at_time(now)[0], 1)
                if progress == 1 and self._get_real_progress() >= 1:
                    # Do not exit until both the model and the actual progress reach 100% mark.
                    break
                result = self._widget.render(progress)
                assert_is_type(result, RenderResult)
                time0 = result.next_time
                time1 = self._get_time_at_progress(result.next_progress)
                next_render_time = min(time0, time1)
                self._draw(result.rendered)

                # Wait until the next rendering/querying cycle
                wait_time = min(next_render_time, self._next_poll_time) - now
                if wait_time > 0:
                    time.sleep(wait_time)
                    if print_verbose_info is not None:
                        print_verbose_info(progress)
        except KeyboardInterrupt:
            # If the user presses Ctrl+C, we interrupt the progress bar.
            status = "cancelled"
        except StopIteration as e:
            # If the generator raises StopIteration before reaching 100%, then the progress display will
            # reamin incomplete.
            status = str(e)

        # Do one final rendering before we exit
        result = self._widget.render(progress=progress, status=status)
        self._draw(result.rendered, final=True)

        if status == "cancelled":
            # Re-raise the exception, to inform the upstream caller that something unexpected happened.
            raise StopIteration(status)
Start the progress bar, and return only when the progress reaches 100%.

        :param progress_fn: the executor function (or a generator). This function should take no arguments
            and return either a single number -- the current progress level, or a tuple (progress level, delay),
            where delay is the time interval for when the progress should be checked again. This function may at
            any point raise the ``StopIteration(message)`` exception, which will interrupt the progress bar,
            display the ``message`` in red font, and then re-raise the exception.
        :raises StopIteration: if the job is interrupted. The reason for interruption is provided in the exception's
            message. The message will say "cancelled" if the job was interrupted by the user by pressing Ctrl+C.