Ejemplo n.º 1
0
    def _get_format_callable(term, color, back_color):
        """Get string-coloring callable

        Get callable for string output using ``color`` on ``back_color``
            on ``term``

        :param term: blessings.Terminal instance
        :param color: Color that callable will color the string it's passed
        :param back_color: Back color for the string
        :returns: callable(s: str) -> str
        """
        if isinstance(color, str):
            ensure(
                any(isinstance(back_color, t) for t in [str, type(None)]),
                TypeError,
                "back_color must be a str or NoneType"
            )
            if back_color:
                return getattr(term, "_".join(
                    [color, "on", back_color]
                ))
            elif back_color is None:
                return getattr(term, color)
        elif isinstance(color, int):
            return term.on_color(color)
        else:
            raise TypeError("Invalid type {} for color".format(
                type(color)
            ))
Ejemplo n.º 2
0
    def _write(self, s, s_length=None, flush=False, ignore_overflow=False,
               err_msg=None):
        """Write ``s``

        :type  s: str|unicode
        :param s: String to write
        :param s_length: Custom length of ``s``
        :param flush: Set this to flush the terminal stream after writing
        :param ignore_overflow: Set this to ignore if s will exceed
            the terminal's width
        :param err_msg: The error message given to WidthOverflowError
            if it is triggered
        """
        if not ignore_overflow:
            s_length = len(s) if s_length is None else s_length
            if err_msg is None:
                err_msg = (
                    "Terminal has {} columns; attempted to write "
                    "a string {} of length {}.".format(
                        self.columns, repr(s), s_length)
                )
            ensure(s_length <= self.columns, WidthOverflowError, err_msg)
        self.cursor.write(s)
        if flush:
            self.cursor.flush()
Ejemplo n.º 3
0
    def _write(self,
               s,
               s_length=None,
               flush=False,
               ignore_overflow=False,
               err_msg=None):
        """Write ``s``

        :type  s: str|unicode
        :param s: String to write
        :param s_length: Custom length of ``s``
        :param flush: Set this to flush the terminal stream after writing
        :param ignore_overflow: Set this to ignore if s will exceed
            the terminal's width
        :param err_msg: The error message given to WidthOverflowError
            if it is triggered
        """
        if not ignore_overflow:
            s_length = len(s) if s_length is None else s_length
            if err_msg is None:
                err_msg = ("Terminal has {} columns; attempted to write "
                           "a string {} of length {}.".format(
                               self.columns, repr(s), s_length))
            ensure(s_length <= self.columns, WidthOverflowError, err_msg)
        self.cursor.write(s)
        if flush:
            self.cursor.flush()
Ejemplo n.º 4
0
    def _supports_colors(term, raise_err, colors):
        """Check if ``term`` supports ``colors``

        :raises ColorUnsupportedError: This is raised if ``raise_err``
            is ``False`` and a color in ``colors`` is unsupported by ``term``
        :type raise_err: bool
        :param raise_err: Set to ``False`` to return a ``bool`` indicating
            color support rather than raising ColorUnsupportedError
        :type  colors: [str, ...]
        """
        for color in colors:
            try:
                if isinstance(color, str):
                    req_colors = 16 if "bright" in color else 8
                    ensure(term.number_of_colors >= req_colors,
                           ColorUnsupportedError,
                           "{} is unsupported by your terminal.".format(color))
                elif isinstance(color, int):
                    ensure(term.number_of_colors >= color,
                           ColorUnsupportedError,
                           "{} is unsupported by your terminal.".format(color))
            except ColorUnsupportedError as e:
                if raise_err:
                    raise e
                else:
                    return False
        else:
            return True
Ejemplo n.º 5
0
    def _supports_colors(term, raise_err, colors):
        """Check if ``term`` supports ``colors``

        :raises ColorUnsupportedError: This is raised if ``raise_err``
            is ``False`` and a color in ``colors`` is unsupported by ``term``
        :type raise_err: bool
        :param raise_err: Set to ``False`` to return a ``bool`` indicating
            color support rather than raising ColorUnsupportedError
        :type  colors: [str, ...]
        """
        for color in colors:
            try:
                if isinstance(color, str):
                    req_colors = 16 if "bright" in color else 8
                    ensure(term.number_of_colors >= req_colors,
                           ColorUnsupportedError,
                           "{} is unsupported by your terminal.".format(color))
                elif isinstance(color, int):
                    ensure(term.number_of_colors >= color,
                           ColorUnsupportedError,
                           "{} is unsupported by your terminal.".format(color))
            except ColorUnsupportedError as e:
                if raise_err:
                    raise e
                else:
                    return False
        else:
            return True
Ejemplo n.º 6
0
    def _get_format_callable(term, color, back_color):
        """Get string-coloring callable

        Get callable for string output using ``color`` on ``back_color``
            on ``term``

        :param term: blessings.Terminal instance
        :param color: Color that callable will color the string it's passed
        :param back_color: Back color for the string
        :returns: callable(s: str) -> str
        """
        if isinstance(color, str):
            ensure(any(isinstance(back_color, t)
                       for t in [str, type(None)]), TypeError,
                   "back_color must be a str or NoneType")
            if back_color:
                return getattr(term, "_".join([color, "on", back_color]))
            elif back_color is None:
                return getattr(term, color)
        elif isinstance(color, int):
            return term.on_color(color)
        else:
            raise TypeError("Invalid type {} for color".format(type(color)))
Ejemplo n.º 7
0
    def draw(self, tree, bar_desc=None, save_cursor=True, flush=True):
        """Draw ``tree`` to the terminal

        :type  tree: dict
        :param tree: ``tree`` should be a tree representing a hierarchy; each
            key should be a string describing that hierarchy level and value
            should also be ``dict`` except for leaves which should be
            ``BarDescriptors``. See ``BarDescriptor`` for a tree example.
        :type  bar_desc: BarDescriptor|NoneType
        :param bar_desc: For describing non-leaf bars in that will be
            drawn from ``tree``; certain attributes such as ``value``
            and ``kwargs["max_value"]`` will of course be overridden
            if provided.
        :type  flush: bool
        :param flush: If this is set, output written will be flushed
        :type  save_cursor: bool
        :param save_cursor: If this is set, cursor location will be saved before
            drawing; this will OVERWRITE a previous save, so be sure to set
            this accordingly (to your needs).
        """
        if save_cursor:
            self.cursor.save()

        tree = deepcopy(tree)
        # TODO: Automatically collapse hierarchy so something
        #   will always be displayable (well, unless the top-level)
        #   contains too many to display
        lines_required = self.lines_required(tree)
        ensure(lines_required <= self.cursor.term.height,
               LengthOverflowError,
               "Terminal is not long ({} rows) enough to fit all bars "
               "({} rows).".format(self.cursor.term.height, lines_required))
        bar_desc = BarDescriptor(type=Bar) if not bar_desc else bar_desc
        self._calculate_values(tree, bar_desc)
        self._draw(tree)
        if flush:
            self.cursor.flush()
Ejemplo n.º 8
0
    def draw(self, tree, bar_desc=None, save_cursor=True, flush=True):
        """Draw ``tree`` to the terminal

        :type  tree: dict
        :param tree: ``tree`` should be a tree representing a hierarchy; each
            key should be a string describing that hierarchy level and value
            should also be ``dict`` except for leaves which should be
            ``BarDescriptors``. See ``BarDescriptor`` for a tree example.
        :type  bar_desc: BarDescriptor|NoneType
        :param bar_desc: For describing non-leaf bars in that will be
            drawn from ``tree``; certain attributes such as ``value``
            and ``kwargs["max_value"]`` will of course be overridden
            if provided.
        :type  flush: bool
        :param flush: If this is set, output written will be flushed
        :type  save_cursor: bool
        :param save_cursor: If this is set, cursor location will be saved before
            drawing; this will OVERWRITE a previous save, so be sure to set
            this accordingly (to your needs).
        """
        if save_cursor:
            self.cursor.save()

        tree = deepcopy(tree)
        # TODO: Automatically collapse hierarchy so something
        #   will always be displayable (well, unless the top-level)
        #   contains too many to display
        lines_required = self.lines_required(tree)
        ensure(
            lines_required <= self.cursor.term.height, LengthOverflowError,
            "Terminal is not long ({} rows) enough to fit all bars "
            "({} rows).".format(self.cursor.term.height, lines_required))
        bar_desc = BarDescriptor(type=Bar) if not bar_desc else bar_desc
        self._calculate_values(tree, bar_desc)
        self._draw(tree)
        if flush:
            self.cursor.flush()
Ejemplo n.º 9
0
    def max_width(self):
        """Get maximum width of progress bar

        :rtype: int
        :returns: Maximum column width of progress bar
        """
        value, unit = float(self._width_str[:-1]), self._width_str[-1]

        ensure(unit in ["c", "%"], ValueError,
               "Width unit must be either 'c' or '%'")

        if unit == "c":
            ensure(value <= self.columns, ValueError,
                   "Terminal only has {} columns, cannot draw "
                   "bar of size {}.".format(self.columns, value))
            retval = value
        else:  # unit == "%"
            ensure(0 < value <= 100, ValueError,
                   "value=={} does not satisfy 0 < value <= 100".format(value))
            dec = value / 100
            retval = dec * self.columns

        return floor(retval)
Ejemplo n.º 10
0
    def max_width(self):
        """Get maximum width of progress bar

        :rtype: int
        :returns: Maximum column width of progress bar
        """
        value, unit = float(self._width_str[:-1]), self._width_str[-1]

        ensure(unit in ["c", "%"], ValueError,
               "Width unit must be either 'c' or '%'")

        if unit == "c":
            ensure(
                value <= self.columns, ValueError,
                "Terminal only has {} columns, cannot draw "
                "bar of size {}.".format(self.columns, value))
            retval = value
        else:  # unit == "%"
            ensure(0 < value <= 100, ValueError,
                   "value=={} does not satisfy 0 < value <= 100".format(value))
            dec = value / 100
            retval = dec * self.columns

        return floor(retval)
Ejemplo n.º 11
0
    def __init__(
            self, term=None, max_value=100, width="25%", title_pos="left",
            title="Progress", num_rep="fraction", indent=0, filled_color=2,
            empty_color=7, back_color=None, filled_char=u' ',
            empty_char=u' ', start_char=u'', end_char=u'', fallback=True,
            fallback_empty_char=u'◯', fallback_filled_char=u'◉',
            force_color=None
    ):
        self.cursor = Cursor(term)
        self.term = self.cursor.term

        self._measure_terminal()

        self._width_str = width
        self._max_value = max_value

        ensure(title_pos in ["left", "right", "above", "below"], ValueError,
               "Invalid choice for title position.")
        self._title_pos = title_pos
        self._title = title
        ensure(num_rep in ["fraction", "percentage"], ValueError,
               "num_rep must be either 'fraction' or 'percentage'.")
        self._num_rep = num_rep
        ensure(indent < self.columns, ValueError,
               "Indent must be smaller than terminal width.")
        self._indent = indent

        self._start_char = start_char
        self._end_char = end_char

        # Setup callables and characters depending on if terminal has
        #   has color support
        if force_color is not None:
            supports_colors = force_color
        else:
            supports_colors = self._supports_colors(
                term=self.term,
                raise_err=not fallback,
                colors=(filled_color, empty_color)
            )
        if supports_colors:
            self._filled_char = filled_char
            self._empty_char = empty_char
            self._filled = self._get_format_callable(
                term=self.term,
                color=filled_color,
                back_color=back_color
            )
            self._empty = self._get_format_callable(
                term=self.term,
                color=empty_color,
                back_color=back_color
            )
        else:
            self._empty_char = fallback_empty_char
            self._filled_char = fallback_filled_char
            self._filled = self._empty = lambda s: s

        ensure(self.full_line_width <= self.columns, WidthOverflowError,
               "Attempting to initialize Bar with full_line_width {}; "
               "terminal has width of only {}.".format(
                   self.full_line_width,
                   self.columns))
Ejemplo n.º 12
0
    def __init__(self,
                 term=None,
                 max_value=100,
                 width="25%",
                 title_pos="left",
                 title="Progress",
                 num_rep="fraction",
                 indent=0,
                 filled_color=2,
                 empty_color=7,
                 back_color=None,
                 filled_char=u' ',
                 empty_char=u' ',
                 start_char=u'',
                 end_char=u'',
                 fallback=True,
                 fallback_empty_char=u'◯',
                 fallback_filled_char=u'◉',
                 force_color=None):
        self.cursor = Cursor(term)
        self.term = self.cursor.term

        self._measure_terminal()

        self._width_str = width
        self._max_value = max_value

        ensure(title_pos in ["left", "right", "above", "below"], ValueError,
               "Invalid choice for title position.")
        self._title_pos = title_pos
        self._title = title
        ensure(num_rep in ["fraction", "percentage"], ValueError,
               "num_rep must be either 'fraction' or 'percentage'.")
        self._num_rep = num_rep
        ensure(indent < self.columns, ValueError,
               "Indent must be smaller than terminal width.")
        self._indent = indent

        self._start_char = start_char
        self._end_char = end_char

        # Setup callables and characters depending on if terminal has
        #   has color support
        if force_color is not None:
            supports_colors = force_color
        else:
            supports_colors = self._supports_colors(term=self.term,
                                                    raise_err=not fallback,
                                                    colors=(filled_color,
                                                            empty_color))
        if supports_colors:
            self._filled_char = filled_char
            self._empty_char = empty_char
            self._filled = self._get_format_callable(term=self.term,
                                                     color=filled_color,
                                                     back_color=back_color)
            self._empty = self._get_format_callable(term=self.term,
                                                    color=empty_color,
                                                    back_color=back_color)
        else:
            self._empty_char = fallback_empty_char
            self._filled_char = fallback_filled_char
            self._filled = self._empty = lambda s: s

        ensure(
            self.full_line_width <= self.columns, WidthOverflowError,
            "Attempting to initialize Bar with full_line_width {}; "
            "terminal has width of only {}.".format(self.full_line_width,
                                                    self.columns))