예제 #1
0
    def test_sanity(self):
        unicode_ = 0x1F352
        # instance
        instance_ = Unicode.parse(unicode_)
        # expected
        test_ = CjTest(instance_)
        test_.add_check(test_.name == "CHERRIES", test_.value == '\U0001F352',
                        test_.decimal == 127826,
                        test_.bin == "0b11111001101010010",
                        test_.hex == "0x1f352", test_.oct == '0o371522')

        test_.check_all()
예제 #2
0
class _StateTime(State):
    __clock = Unicode("\U0001F55C")
    __max_sequence = 12
    size = 11

    def display(self, current_value: Number, max_value: Number,
                current_percent: Number, time_it: Number, n_times: int) -> str:
        time_estimate = estimate(current_value, max_value, time_it)
        idx = int(proportional(int(current_percent), self.__max_sequence))
        t_format = f"{time_format(time_estimate)}"
        value = f"{self.__clock + idx} {t_format}"
        return f"{value}{self.blanks(len(value))} estimated"

    def done(self, current_value: Number, max_value: Number,
             current_percent: Number, time_it: Number, n_times: float) -> str:
        return f"{self.__clock} {time_format(time_it)} total"
예제 #3
0
class ProgressBase:
    __awaiting_state = _StateAwaiting()
    __done_unicode = Unicode("\U00002705")
    __err_unicode = Unicode("\U0000274C")
    __key_map = {
        "loading": _StateLoading,
        "time": _StateTime,
        "percent": _StatePercent,
        "bar": _StateBar
    }

    def __init__(self, max_value: int = 100, states=None):
        self._builded = False
        self.n_times = 0
        self.__name = self.set_name("Cereja Progress Tool")
        self.__task_count = 0
        self.started = False
        self._awaiting_update = True
        self._show = False
        self.console = console
        self.started_time = None
        self._states = ()
        self.add_state(states)
        self.max_value = max_value
        self._current_value = 0
        self.th_root = self._create_progress_service()
        self._with_context = False
        self._was_done = False
        self._err = False
        self._builded = True

    @property
    def name(self):
        return self.__name

    def set_name(self, value: str):
        if not isinstance(value, str):
            raise TypeError("Please send string.")
        self.__name = value

    def _create_progress_service(self):
        return threading.Thread(name="awaiting", target=self._progress_service)

    def __repr__(self):
        state, _ = self._states_view(self.max_value)
        progress_example_view = f"{state}"
        state_conf = f"{self.__class__.__name__}{self._parse_states()}"
        return f"{state_conf}\n{self.console.parse(progress_example_view, title='Example States View')}"

    def hook_error(self, *args, **kwargs):
        self._err = True
        if not self._with_context:
            self.stop()

    def _parse_states(self):
        return tuple(map(lambda stt: stt.__class__.__name__, self._states))

    def _get_done_state(self, **kwargs):
        result = list(map(lambda state: state.done(**kwargs), self._states))
        done_msg = f"Done! {self.__done_unicode}"
        done_msg = self.console.format(done_msg, 'green')
        result.append(done_msg)
        return result

    def _get_error_state(self):
        result, _ = self._states_view(self._current_value)
        error_msg = f"Error! {self.__err_unicode}"
        error_msg = self.console.format(error_msg, 'red')
        return f'{result} {error_msg}'

    def _get_state(self, **kwargs):
        return list(map(lambda state: state.display(**kwargs), self._states))

    @property
    def time_it(self):
        return time.time() - (self.started_time or time.time())

    def _states_view(self, for_value: Number) -> Tuple[str, bool]:
        """
        Return current state and bool
        bool:
        :param for_value:
        :return: current state and bool if is done else False
        """
        self.n_times += 1
        kwargs = {
            "current_value": for_value,
            "max_value": self.max_value,
            "current_percent": self.percent_(for_value),
            "time_it": self.time_it,
            "n_times": self.n_times
        }
        if for_value >= self.max_value:
            return ' - '.join(self._get_done_state(**kwargs)), True

        return ' - '.join(self._get_state(**kwargs)), False

    def add_state(self, state: Union[State, Sequence[State]], idx=-1):
        self._filter_and_add_state(state, idx)

    def remove_state(self, idx):
        states = list(self._states)
        states.pop(idx)
        self._states = tuple(states)

    def _valid_states(self, states: Union[State, Sequence[State]]):
        if states is not None:
            if not is_iterable(states):
                states = (states, )
            return tuple(
                map(lambda st: st if isinstance(st, State) else st(), states))
        return None,

    def _filter_and_add_state(self,
                              state: Union[State, Sequence[State]],
                              index_=-1):
        state = self._valid_states(state)
        filtered = tuple(
            filter(lambda stt: stt not in self._states, tuple(state)))
        if any(filtered):
            if index_ == -1:
                self._states += filtered
            else:
                states = list(self._states)
                for idx, new_state in enumerate(filtered):
                    states.insert(index_ + idx, new_state)
                self._states = tuple(states)
            if self._builded:
                self.console.log(f"Added new states! {filtered}")

    @property
    def states(self):
        return self._parse_states()

    def percent_(self, for_value: Number) -> Number:
        return percent(for_value, self.max_value)

    def update_max_value(self, max_value: int):
        """
        You can modify the progress to another value. It is not a percentage,
        although it is purposely set to 100 by default.

        :param max_value: This number represents the maximum amount you want to achieve.
        """
        if not isinstance(max_value, (int, float, complex)):
            raise Exception(f"Current value {max_value} isn't valid.")
        if max_value != self.max_value:
            self.max_value = max_value

    def _progress_service(self):
        last_value = self._current_value
        n_times = 0
        while self.started:
            if (self._awaiting_update
                    and self._current_value != last_value) or not self._show:
                n_times += 1
                self.console.replace_last_msg(
                    self.__awaiting_state.display(0, 0, 0, 0, n_times=n_times))
                time.sleep(0.5)
            if not self._awaiting_update or self._show:
                self._show_progress(self._current_value)
            last_value = self._current_value
            time.sleep(0.01)
        if not self._was_done:
            self._show_progress(self.max_value)

    def _show_progress(self, for_value=None):
        self._awaiting_update = False
        build_progress, is_done = self._states_view(for_value)
        end = '\n' if is_done else None

        if self._err:
            self.console.replace_last_msg((self._get_error_state()))
        if not self._was_done and not self._err:
            self.console.replace_last_msg(build_progress, end=end)
        if is_done:
            self._show = False
            self._awaiting_update = True
            self._was_done = True
        else:
            self._was_done = False

    def _update_value(self, value):
        self._awaiting_update = False
        self._show = True
        self._current_value = value

    def show_progress(self, for_value, max_value=None):
        """
        Build progress by a value.

        :param for_value: Fraction of the "max_value" you want to achieve.
                              Remember that this value is not necessarily the percentage.
                              It is totally dependent on the "max_value"
        :param max_value: This number represents the maximum amount you want to achieve.
                          It is not a percentage, although it is purposely set to 100 by default.
        """
        if max_value is not None:
            self.update_max_value(max_value)
        self._update_value(for_value)

    def _reset(self):
        self._current_value = 0
        self.n_times = 0
        self.started_time = None

    def start(self):
        if self.started:
            return
        self.started_time = time.time()
        self.started = True
        try:
            self.th_root.start()
        except:
            self.th_root.join()
            self.th_root = self._create_progress_service()
            self.th_root.start()
        self.console.persist_on_runtime()
        self.n_times = 0

    def stop(self):
        if self.started:
            self._awaiting_update = False
            self.started = False
            self.th_root.join()
            self.console.disable()

    def restart(self):
        self._reset()

    def __len__(self):
        return len(self._states)

    def __getitem__(self, slice_):
        if isinstance(slice_, tuple):
            if max(slice_) > len(self):
                raise IndexError(f"{max(slice_)} isn't in progress")
            return tuple(self._states[idx] for idx in slice_
                         if idx < len(self))
        if isinstance(slice_, str):
            key = self.__key_map[slice_]
            if key in self._states:
                slice_ = self._states.index(key)
            else:
                raise KeyError(f"Not exists {key}")
        return self._states[slice_]

    def __call__(self, sequence: Sequence, task_name=None) -> "ProgressBase":
        if not is_iterable(sequence):
            raise ValueError("Send a sequence.")
        self.update_max_value(len(sequence))
        self.sequence = sequence
        if task_name is not None:
            self.console.set_prefix(f"{self.name}({task_name})")
        if self._with_context and task_name is None:
            self.console.set_prefix(f"{self.name}(iter-{self.__task_count})")
        self.started_time = time.time()
        self.__task_count += 1
        return self

    def __next__(self):
        if not self._with_context:
            self.start()
        for n, obj in enumerate(self.sequence):
            self._update_value(n + 1)
            yield obj
        if not self._with_context:
            self.stop()
        self.console.set_prefix(self.name)
        self.sequence = ()

    def __iter__(self):
        return self.__next__()

    def __setitem__(self, key, value):
        value = self._valid_states(value)[0]
        if isinstance(value, State):
            value = value
            if isinstance(key, int):
                states_ = list(self._states)
                states_[key] = value
                self._states = tuple(states_)
        else:
            raise ValueError("Please send State object")

    def __enter__(self, *args, **kwargs):
        if hasattr(self, 'sequence'):
            raise ChildProcessError(
                "Dont use progress instance on with statement.")
        self._with_context = True
        self.start()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if isinstance(exc_val, Exception) and not isinstance(
                exc_val, DeprecationWarning):
            self.console.error(
                f'{os.path.basename(exc_tb.tb_frame.f_code.co_filename)}:{exc_tb.tb_lineno}: {exc_val}'
            )
        self.stop()
        self.__task_count = 0
        self._with_context = False