Source code for framed_text.labeled_data

import textwrap
from datetime import datetime
from pathlib import Path
from typing import Literal, Any

from framed_text.color import Color
from framed_text.utils import (
    _format_col_text,
    _format_big_number,
    _human_readable_bytes,
    _remove_ansi,
    _truncate_text_middle,
    _validate_attrs,
)


[docs] class LabeledData: """ Class for creating a string with a label and different types of data. Each item can be configured to include colored text. """ class _Base: def __init__(self, ld_type: str, label: str, value: Any, suffix: str = '', quotes: bool = True, colon_match: bool = True, no_colon: bool = False, label_color: Color | None = None, val_color: Color | None = None, suffix_color: Color | None = None, label_attrs: list[str] | None = None, val_attrs: list[str] | None = None, suffix_attrs: list[str] | None = None, **params): """ Base class for LabeledData classes. :param ld_type: Type of LabeledData. Used for formatting different data types. :param label: Label :param value: Value :param suffix: Optional text to appear after the value :param quotes: If true, wrap text in single quotes (') :param colon_match: If true, the colon will match the style of the label. :param no_colon: If true, the colon will be removed. Overrides ``colon_match`` :param label_color: Color of label. :param val_color: Color of string value. :param label_attrs: Attributes to apply to the label. :param val_attrs: Attributes to apply to the value. :param suffix_color: Color of suffix :param params: Additional class-specific parameters """ self._ld_type: str = ld_type.lower() self._label: str = label self._value: Any = value self._suffix: str = suffix self._quotes: bool = quotes self._colon_match: bool = colon_match self._no_colon: bool = no_colon self._label_color: Color = label_color if label_color else Color() self._val_color: Color = val_color if val_color else Color() self._suffix_color: Color = suffix_color if suffix_color else Color() self._label_attrs: list[str] | None = _validate_attrs(attrs=label_attrs) self._val_attrs: list[str] | None = _validate_attrs(attrs=val_attrs) self._suffix_attrs: list[str] | None = _validate_attrs(attrs=suffix_attrs) self._params: dict[str, Any] = params # Parse params self._parse_params() self.text_shorten: str = '' self.text: str = self._format_text() def __str__(self) -> str: return self.text def _parse_params(self): """ Parse any additional parameters passed to the class. ``self._value`` will be updated based on params. """ match self._ld_type: case "number": # If number is large (>32-bit integer), format to E-Notation # Will override rounding and leading zeros if abs(self._value) > 0xffffffff: self._value = _format_big_number(num=self._value) else: # Rounding if self._params["int_no_round"]: # Display num as integer self._value = f"{int(self._value):,}" elif self._params["round_to"] is not None and self._params["round_to"] > 0: # Round self._value = f"{round(self._value, self._params["round_to"]):,}" elif self._params["round_to"] is not None and self._params["round_to"] == 0: # Round to Integer. Don't display trailing 0 self._value = f"{round(self._value, self._params["round_to"]):,.0f}" elif self._params["round_to"]: # Round error raise ValueError("'round' must be an integer greater than 0") else: # No rounding self._value = f"{self._value:,}" # Leading Zeros if self._params["leading_zeros"] and self._params["leading_zeros"] >= 0: self._value = f"{self._value:0{self._params["leading_zeros"]}d}" elif self._params["leading_zeros"]: # Leading zeros error raise ValueError("'leading_zeros' must be an integer greater than 0") case "date": # If strftime was passed, format time if self._params["strftime"] and not self._value: # No value, use current time self._value = datetime.now().strftime(self._params["strftime"]) elif self._params["strftime"] and isinstance(self._value, datetime): # Format value self._value = self._value.strftime(self._params["strftime"]) case "bytes": # Validate unit style vars self._params["unit_color"] = self._params["unit_color"] if self._params["unit_color"] else Color() self._params["unit_attrs"] = _validate_attrs(attrs=self._params["unit_attrs"]) def _format_text(self, label: str = '', value: str = '', suffix: str = '') -> str: # Label _label: str = _format_col_text(text=label if label else self._label, color=self._label_color.tc_color, attrs=self._label_attrs) # Colon if needed if self._colon_match and not self._no_colon: _col: str = _format_col_text(text=':', color=self._label_color.tc_color) elif not self._no_colon: _col: str = ':' else: _col: str = '' # Suffix _suffix: str = _format_col_text(text=suffix if suffix else self._suffix, color=self._suffix_color.tc_color, attrs=self._suffix_attrs) # Value if value: _value: str = _format_col_text(text=f"'{value}'" if self._quotes else value, color=self._val_color.tc_color, attrs=self._val_attrs) elif self._ld_type == "bytes": # Unit & Value _byte_val, _unit = _human_readable_bytes(value=self._value, unit_type=self._params["unit_type"]) _unit_color: Color = self._params["unit_color"] or Color() _unit_attrs: list[str] | None = self._params["unit_attrs"] # Add unit to params self._params["unit"] = _unit # Override unit_match if a unit color/attr is passed if self._params["unit_match"]: _unit_color = self._val_color if not _unit_color.tc_color else _unit_color _unit_attrs = self._val_attrs if not _unit_attrs else _unit_attrs if self._params["show_unit"]: # If the value is large (Over 32 bits), format it to E-Notation if _byte_val and abs(_byte_val) > 0xffffffff: _val: str = _format_big_number(num=_byte_val) elif _byte_val: _val: str = f"{_byte_val:,.2f}" elif abs(self._value) > 0xffffffff: _val: str = _format_big_number(num=self._value) else: _val: str = str(self._value) _unit_txt: str = _format_col_text(text=_unit, color=_unit_color.tc_color, attrs=_unit_attrs) else: _val: str = str(self._value) _unit_txt: str = '' _val = _format_col_text(text=_val, color=self._val_color.tc_color, attrs=self._val_attrs) _value: str = f"'{_val} {_unit_txt}'" if self._quotes else f"{_val} {_unit_txt}" else: if self._quotes: _value: str = _format_col_text(text=f"'{self._value}'", color=self._val_color.tc_color, attrs=self._val_attrs) else: _value: str = _format_col_text(text=str(self._value), color=self._val_color.tc_color, attrs=self._val_attrs) if self._suffix != '': return f"{_label}{_col} {_value} {_suffix}" else: return f"{_label}{_col} {_value}" def _cutoff_text(self, limit: int, mode: Literal["char", "word", "middle"] | None = None) -> str: """ Main types of text cutoff: - String: Shorten everything - Numbers: Shorten everything, except value (Bytes: unit) - Path: Custom version of String """ if len(self.text) <= limit: # Under or at limit return self.text # Limit calc _limit: int = limit - 2 if self._quotes else limit # Quotes _limit -= 1 if self._no_colon else 2 # Colon + space # Setup mode _mode: Literal["char", "word", "middle"] = "char" if self._ld_type == "date": _mode = "word" elif mode: _mode = mode _suffix: str = '' match self._ld_type: case "string" | "boolean" | "date": # Shorten everything _limit, _label = self._shorten_label(label=self._label, limit=_limit) if self._suffix: _value, _suffix = self._shorten_val_suffix(value=str(self._value), suffix=self._suffix, limit=_limit, mode=_mode) else: _limit, _value = self._shorten_value(value=str(self._value), limit=_limit, mode=_mode) # Format text self.text_shorten = self._format_text(label=_label, value=_value, suffix=_suffix) case "number" | "bytes": # Shorten everything, except value # Bytes also doesn't shorten the unit _limit, _label = self._shorten_label(label=self._label, limit=_limit) # Calculate limit for suffix vna_len: int = len(_remove_ansi(str(self._value))) _limit -= vna_len if self._ld_type == "bytes": # Unit calculation una_len: int = len(_remove_ansi(self._params["unit"])) _limit -= una_len # Ensure there's enough space for suffix ellipsis _limit = max(1, _limit - 1) _suffix = self._shorten_suffix(suffix=self._suffix, limit=_limit) # Format text self.text_shorten = self._format_text(label=_label, suffix=_suffix) case _: # Same as string, except custom logic for value _limit, _label = self._shorten_label(label=self._label, limit=_limit) # -------------------------------------------------------------------------------------------- # Other LD types with different logic go below here # -------------------------------------------------------------------------------------------- _value: str = '' if self._ld_type == "path": _value, _suffix = self._shorten_path(value=str(self._value), suffix=self._suffix, limit=_limit, mode=_mode) # Format text if self._suffix != '': self.text_shorten = self._format_text(label=_label, value=_value, suffix=_suffix) else: self.text_shorten = self._format_text(label=_label, value=_value) return self.text_shorten # ============================================================================================ # HELPER FUNCTIONS FOR CUTOFF GO HERE # ============================================================================================ @staticmethod def _get_val_suffix_limits(vna_len: int, sna_len: int, limit: int) -> tuple[int, int]: """ Get the value and suffix limits :param vna_len: Length of value without ANSI :param sna_len: Length of suffix without ANSI :param limit: # of characters to limit the value and suffix to :return: value limit, suffix limit """ # Calculate limit _limit: int = limit - 1 if sna_len > 0 else limit # Space before suffix _limit -= 1 # Value ellipsis due to char mode if vna_len + sna_len <= _limit: # Value and suffix under limit. No work needed return -1, -1 # Calculate ratio between value and suffix favor_ratio: float = 0.75 if vna_len <= (_limit * favor_ratio): # Favor value limit_ratio: float = favor_ratio # Only take up as much space as needed favor_len: int = round(_limit * limit_ratio) value_limit: int = min(vna_len, favor_len) suffix_limit: int = _limit - value_limit else: # Favor whichever is longer limit_ratio: float = vna_len / (vna_len + sna_len) value_limit: int = round(_limit * limit_ratio) suffix_limit: int = _limit - value_limit return value_limit, suffix_limit # ============================================================================================ # FUNCTIONS FOR CUTOFF: Each function should handle a specific part of the text # ============================================================================================ @staticmethod def _shorten_label(label: str, limit: int) -> tuple[int, str]: """ Shorten the label portion of the text :param label: Label :param limit: # of characters to limit the label to :return: Limit, shortened label """ # Remove ANSI label_no_ansi: str = _remove_ansi(text=label) lna_len: int = len(label_no_ansi) # Calculate label's limit label_limit: int = limit - lna_len if lna_len <= limit // 2: # Label under limit. No work needed return label_limit, label # Shorten label _label: str = textwrap.shorten(text=label_no_ansi, width=limit // 2, placeholder="…") l_len: int = len(_label) # Add back removed characters to limit label_limit += lna_len - l_len return label_limit, _label @staticmethod def _shorten_value(value: str, limit: int, mode: Literal["char", "word", "middle"]) -> tuple[int, str]: """ Shorten the value portion of the text :param value: Value :param limit: # of characters to limit the value to :param mode: How the text should be shortened. See documentation for details :return: Limit, shortened value """ # Remove ANSI value_no_ansi: str = _remove_ansi(text=value) vna_len: int = len(value_no_ansi) limit -= 1 # Ellipsis due to char mode if vna_len <= limit: # Value under limit. No work needed return limit, value # Shorten value _value: str = '' match mode.lower(): case "char": # Shorten by char _value = f"{value_no_ansi[:limit]}…" case "word": # Shorten by word _value = textwrap.shorten(text=value_no_ansi, width=limit, placeholder="…") case "middle": # Shorten by middle characters _value = _truncate_text_middle(text=value_no_ansi, limit=limit) # Update limit v_len: int = len(_value) value_limit: int = limit + (vna_len - v_len) # Add back removed characters value_limit -= v_len # Subtract new length return value_limit, _value @staticmethod def _shorten_val_suffix(value: str, suffix: str, limit: int, mode: Literal["char", "word", "middle"]) -> tuple[str, str]: """ Shorten both the value and suffix portions of the text. Each will share a ratio of the limit. :param value: Value :param limit: # of characters to limit the value to :param mode: How the text should be shortened. See documentation for details :return: Shortened value & suffix """ # Remove ANSI value_no_ansi: str = _remove_ansi(text=value) suffix_no_ansi: str = _remove_ansi(text=suffix) vna_len: int = len(value_no_ansi) sna_len: int = len(suffix_no_ansi) # Get limits value_limit, suffix_limit = LabeledData._Base._get_val_suffix_limits(vna_len=vna_len, sna_len=sna_len, limit=limit) if value_limit == -1 and suffix_limit == -1: # Value and suffix under limit. No work needed return value, suffix # Shorten value if necessary _value: str = value_no_ansi if vna_len > value_limit: match mode.lower(): case "char": # Shorten by char _value = f"{value_no_ansi[:value_limit]}…" case "word": # Shorten by word _value = textwrap.shorten(text=value_no_ansi, width=value_limit, placeholder="…") case "middle": # Shorten by middle characters _value = _truncate_text_middle(text=value_no_ansi, limit=value_limit) # Shorten suffix if necessary _suffix: str = suffix_no_ansi if sna_len > suffix_limit: # Suffix will always be shortened by word _suffix = textwrap.shorten(text=suffix_no_ansi, width=suffix_limit, placeholder="…") return _value, _suffix # ============================================================================================ # DATA-SPECIFIC CUTOFF FUNCTIONS GO HERE # ============================================================================================ @staticmethod def _shorten_suffix(suffix: str, limit: int) -> str: """ Shorten only the suffix. Limit with value should have been calculated :param suffix: Suffix :param limit: # of characters to limit the value to :return: Shortened suffix """ # Remove ANSI suffix_no_ansi: str = _remove_ansi(text=suffix) sna_len: int = len(suffix_no_ansi) if sna_len <= limit: # Suffix under limit. No work needed return suffix # Shorten suffix return textwrap.shorten(text=suffix_no_ansi, width=limit, placeholder="…") @staticmethod def _shorten_path(value: str, suffix: str, limit: int, mode: Literal["char", "word", "middle"]) -> tuple[str, str]: """ Shorten the value and suffix (if any) of a path :param value: Value :param suffix: Suffix :param limit: # of characters to limit the value to :param mode: How the text should be shortened. See documentation for details :return: Shortened value and suffix (if any) """ # Remove ANSI value_no_ansi: str = _remove_ansi(text=value) suffix_no_ansi: str = _remove_ansi(text=suffix) vna_len: int = len(value_no_ansi) sna_len: int = len(suffix_no_ansi) # Get limits value_limit, suffix_limit = LabeledData._Base._get_val_suffix_limits(vna_len=vna_len, sna_len=sna_len, limit=limit) if value_limit == -1 and suffix_limit == -1: # Value and suffix under limit. No work needed return value, suffix # Shorten value if necessary _value: str = value_no_ansi if vna_len > value_limit: match mode.lower(): case "char": # Shorten by char _value = f"{value_no_ansi[:value_limit]}…" case "word": # Shorten by word # Removing leading/trailing slash if value_no_ansi[-1] == "/": value_no_ansi = value_no_ansi[:-1] if value_no_ansi[0] == "/": value_no_ansi = value_no_ansi[1:] # Split path to count text_parts: list[str] = value_no_ansi.split("/") # Remove last part and slashes from limit value_limit -= len(text_parts[-1]) value_limit -= value.count('/') char_cnt: int = 0 part_at_limit: int = -1 # Find which part exceeds limit for i, part in enumerate(text_parts): char_cnt += len(part) if char_cnt > value_limit: part_at_limit = i break if part_at_limit != -1: # Cut of part, replace with ellipsis part_end: str = text_parts[-1] text_parts = text_parts[:part_at_limit] text_parts.insert(part_at_limit, "…") _value = f"/{'/'.join(text_parts)}/{part_end}" else: # No part exceeds limit _value = value_no_ansi case "middle": # Shorten by middle characters _value = _truncate_text_middle(text=value_no_ansi, limit=value_limit) # Shorten suffix if necessary _suffix: str = suffix_no_ansi if sna_len > suffix_limit: # Suffix will always be shortened by word _suffix = textwrap.shorten(text=suffix_no_ansi, width=suffix_limit, placeholder="…") return _value, _suffix
[docs] class String(_Base):
[docs] def __init__(self, label: str, value: str, suffix: str = '', quotes: bool = True, colon_match: bool = True, no_colon: bool = False, label_color: str | tuple[int, int, int] | Color | None = None, val_color: str | tuple[int, int, int] | Color | None = "cyan", suffix_color: str | tuple[int, int, int] | Color | None = None, label_attrs: list[str] | None = None, val_attrs: list[str] | None = None, suffix_attrs: list[str] | None = None): """ Creates a string with a label and string value :param label: Label for string value :param value: String value :param suffix: Optional text to appear after the value :param suffix_color: Color of suffix :param val_color: Color of string value. :param label_color: Color of label. :param quotes: If true, wrap text in single quotes (') :param colon_match: If true, the colon will match the style of the label. :param no_colon: If true, the colon will be removed. Overrides ``colon_match`` :param val_attrs: Attributes to apply to the value. :param label_attrs: Attributes to apply to the label. """ super().__init__( # Main ld_type=self.__class__.__name__, label=label, value=value, suffix=suffix, quotes=quotes, colon_match=colon_match, no_colon=no_colon, label_color=Color(label_color) if label_color else None, val_color=Color(val_color) if val_color else None, suffix_color=Color(suffix_color) if suffix_color else None, label_attrs=label_attrs, val_attrs=val_attrs, suffix_attrs=suffix_attrs )
def __str__(self) -> str: return super().__str__()
[docs] def cutoff_text(self, limit: int, mode: Literal["char", "word", "middle"] = "char") -> str: """ Cuts off text if it exceeds limit. Will first try to shorten string. If there isn't enough space for just an ellipsis, it will try to shorten the label, so that the output will be 50/50 (label: value). Modes: - char: Cutoff char at end of string (The quick brown fox jumped ove…) - word: Cutoff word at end of string (The quick brown fox jumped…) - middle: Cutoff words at middle of string (The quick brown…the lazy dog) :param limit: Maximum length of text :param mode: How to cut off value text :return: Shortened text """ return super()._cutoff_text(limit=limit, mode=mode)
[docs] class Number(_Base):
[docs] def __init__(self, label: str, value: int | float, suffix: str = '', quotes: bool = False, colon_match: bool = True, no_colon: bool = False, round_to: int | None = None, leading_zeros: int | None = None, int_no_round: bool = False, label_color: str | tuple[int, int, int] | Color | None = None, val_color: str | tuple[int, int, int] | Color | None = "yellow", suffix_color: str | tuple[int, int, int] | Color | None = None, label_attrs: list[str] | None = None, val_attrs: list[str] | None = None, suffix_attrs: list[str] | None = None): """ Creates a string with a label and number value :param label: Label for number value :param value: Number value :param suffix: Optional text to appear after the value :param quotes: If true, wrap text in single quotes (') :param colon_match: If true, the colon will match the style of the label. :param no_colon: If true, the colon will be removed. Overrides ``colon_match`` :param round_to: Number of decimal places to round to. Leave blank to not round. :param leading_zeros: Number of leading zeros to add to the number. Leave blank to not add leading zeros. :param int_no_round: If true, displays number as integer without rounding. Overrides ``round_to`` :param label_color: Color of label. :param val_color: Color of number value. :param suffix_color: Color of suffix. :param label_attrs: Attributes to apply to the label. :param val_attrs: Attributes to apply to the value. :param suffix_attrs: Attributes to apply to the suffix. """ super().__init__( # Main ld_type=self.__class__.__name__, label=label, value=value, suffix=suffix, quotes=quotes, colon_match=colon_match, no_colon=no_colon, label_color=Color(label_color) if label_color else None, val_color=Color(val_color) if val_color else None, suffix_color=Color(suffix_color) if suffix_color else None, label_attrs=label_attrs, val_attrs=val_attrs, suffix_attrs=suffix_attrs, # Extra round_to=round_to, leading_zeros=leading_zeros, int_no_round=int_no_round )
def __str__(self) -> str: return super().__str__()
[docs] def cutoff_text(self, limit: int) -> str: """ Cuts off text if it exceeds limit. Will NOT shorten the number, only the suffix (if there is one). If there isn't enough space for just an ellipsis, it will try to shorten the label, so that the output will be 50/50 (label: value). :param limit: Maximum length of text :return: Shortened text """ return super()._cutoff_text(limit=limit)
[docs] class Boolean(_Base):
[docs] def __init__(self, label: str, value: bool, suffix: str = '', t_text: str = "True", f_text: str = "False", quotes: bool = False, colon_match: bool = True, no_colon: bool = False, label_color: str | tuple[int, int, int] | Color | None = None, t_color: str | tuple[int, int, int] | Color | None = "green", f_color: str | tuple[int, int, int] | Color | None = "red", suffix_color: str | tuple[int, int, int] | Color | None = None, label_attrs: list[str] | None = None, val_attrs: list[str] | None = None, suffix_attrs: list[str] | None = None): """ Creates a string with a label and boolean value :param label: Label for boolean value. :param value: Boolean value. :param suffix: Optional text to appear after the value. :param t_text: Text to display for true value. :param f_text: Text to display for false value. :param quotes: If true, wrap text in single quotes (') :param colon_match: If true, the colon will match the style of the label. :param no_colon: If true, the colon will be removed. Overrides ``colon_match`` :param label_color: Color of label. :param t_color: Color of true value. :param f_color: Color of false value. :param suffix_color: Color of suffix. :param label_attrs: Attributes to apply to the label. :param val_attrs: Attributes to apply to the value. :param suffix_attrs: Attributes to apply to the suffix. """ super().__init__( # Main ld_type=self.__class__.__name__, label=label, value=t_text if value else f_text, suffix=suffix, quotes=quotes, colon_match=colon_match, no_colon=no_colon, label_color=Color(label_color) if label_color else None, val_color=Color(t_color) if value else Color(f_color), suffix_color=Color(suffix_color) if suffix_color else None, label_attrs=label_attrs, val_attrs=val_attrs, suffix_attrs=suffix_attrs, )
def __str__(self): return super().__str__()
[docs] def cutoff_text(self, limit: int) -> str: """ Cuts off text if it exceeds limit. Will first try to shorten bool value. If there isn't enough space for just an ellipsis, it will try to shorten the label, so that the output will be 50/50 (label: value). :param limit: Maximum length of text :return: Shortened text """ return super()._cutoff_text(limit=limit)
[docs] class Path(_Base):
[docs] def __init__(self, label: str, value: Path | str, suffix: str = '', quotes: bool = True, colon_match: bool = True, no_colon: bool = False, label_color: str | tuple[int, int, int] | Color | None = None, val_color: str | tuple[int, int, int] | Color | None = "cyan", suffix_color: str | tuple[int, int, int] | Color | None = None, label_attrs: list[str] | None = None, val_attrs: list[str] | None = None, suffix_attrs: list[str] | None = None): """ Creates a string with a label and path to a file or directory :param label: Label for path :param value: Path to file or directory :param suffix: Optional text to appear after the value :param quotes: If true, wrap path in single quotes (') :param colon_match: If true, the colon will match the style of the label. :param no_colon: If true, the colon will be removed. Overrides ``colon_match`` :param label_color: Color of label. :param val_color: Color of path value. :param suffix_color: Color of suffix. :param label_attrs: Attributes to apply to the label. :param val_attrs: Attributes to apply to the value. :param suffix_attrs: Attributes to apply to the suffix. """ super().__init__( # Main ld_type=self.__class__.__name__, label=label, value=value, suffix=suffix, quotes=quotes, colon_match=colon_match, no_colon=no_colon, label_color=Color(label_color) if label_color else None, val_color=Color(val_color) if val_color else None, suffix_color=Color(suffix_color) if suffix_color else None, label_attrs=label_attrs, val_attrs=val_attrs, suffix_attrs=suffix_attrs, )
def __str__(self): return super().__str__()
[docs] def cutoff_text(self, limit: int, mode: Literal["char", "word", "middle"] = "char") -> str: """ Shortens path to limit. Modes: - char: Cutoff char at end of string (/path/to/a/f…) - word: Cutoff path at end, preserve the deepest directory/file (/path/to/…/file.txt) - middle: Cutoff chars at middle of string (/long/path/t…/an/file.txt) :param limit: Character limit for full labeled path string :param mode: How to cut off path. :return: LabeledData.Path string with shortened path if it exceeds limit, else returns original string """ return super()._cutoff_text(limit=limit, mode=mode)
[docs] class Date(_Base):
[docs] def __init__(self, label: str, value: str | datetime = '', suffix: str = '', quotes: bool = True, colon_match: bool = True, no_colon: bool = False, strftime: str = '%Y-%m-%d %H:%M:%S', label_color: str | tuple[int, int, int] | Color | None = None, val_color: str | tuple[int, int, int] | Color | None = "blue", suffix_color: str | tuple[int, int, int] | Color | None = None, label_attrs: list[str] | None = None, val_attrs: list[str] | None = None, suffix_attrs: list[str] | None = None): """ Creates a string with a label and a date value If no value is passed, will print current time using ``strftime`` parameter :param label: Label for string value :param value: Value, either as a datetime object or string :param suffix: Optional text to appear after the value :param quotes: If true, wrap text in single quotes (') :param colon_match: If true, the colon will match the style of the label. :param no_colon: If true, the colon will be removed. Overrides ``colon_match`` :param strftime: Formatter for datetime value :param label_color: Color of label. :param val_color: Color of string value. :param suffix_color: Color of suffix. :param label_attrs: Attributes to apply to the label. :param val_attrs: Attributes to apply to the value. :param suffix_attrs: Attributes to apply to the suffix. """ super().__init__( # Main ld_type=self.__class__.__name__, label=label, value=value, suffix=suffix, quotes=quotes, colon_match=colon_match, no_colon=no_colon, label_color=Color(label_color) if label_color else None, val_color=Color(val_color) if val_color else None, suffix_color=Color(suffix_color) if suffix_color else None, label_attrs=label_attrs, val_attrs=val_attrs, suffix_attrs=suffix_attrs, # Extra strftime=strftime, )
def __str__(self): return super().__str__()
[docs] def cutoff_text(self, limit: int) -> str: """ Cuts off text if it exceeds limit. Will first try to shorten string. If there isn't enough space for just an ellipsis, it will try to shorten the label, so that the output will be 50/50 (label: value). :param limit: Maximum length of text :return: Shortened text """ return super()._cutoff_text(limit=limit)
[docs] class Bytes(_Base):
[docs] def __init__(self, label: str, value: int, suffix: str = '', quotes: bool = False, colon_match: bool = True, no_colon: bool = False, unit_match: bool = True, show_unit: bool = True, unit_type: Literal["iec", "si"] = "iec", label_color: str | tuple[int, int, int] | Color | None = None, val_color: str | tuple[int, int, int] | Color | None = "yellow", unit_color: str | tuple[int, int, int] | Color | None = None, suffix_color: str | tuple[int, int, int] | Color | None = None, label_attrs: list[str] | None = None, val_attrs: list[str] | None = None, unit_attrs: list[str] | None = None, suffix_attrs: list[str] | None = None): """ Creates a string with a label and bytes value :param label: Label for string value :param value: Integer value. Value MUST be in bytes :param suffix: Optional text to appear after the value :param quotes: If true, wrap text in single quotes (') :param colon_match: If true, the colon will match the style of the label. :param no_colon: If true, the colon will be removed. Overrides ``colon_match`` :param show_unit: If true, the unit will be shown. :param unit_match: If true, the unit will match the style of the value. :param unit_type: Unit type: IEC is base 2, SI is base 10 :param label_color: Color of label. :param val_color: Color of string value. :param unit_color: Color of unit. Overrides ``unit_match``. :param suffix_color: Color of suffix. :param label_attrs: Attributes to apply to the label. :param val_attrs: Attributes to apply to the value. :param unit_attrs: Attributes to apply to the unit. Overrides ``unit_match``. :param suffix_attrs: Attributes to apply to the suffix. """ super().__init__( # Main ld_type=self.__class__.__name__, label=label, value=value, suffix=suffix, quotes=quotes, colon_match=colon_match, no_colon=no_colon, label_color=Color(label_color) if label_color else None, val_color=Color(val_color) if val_color else None, suffix_color=Color(suffix_color) if suffix_color else None, label_attrs=label_attrs, val_attrs=val_attrs, suffix_attrs=suffix_attrs, # Extra show_unit=show_unit, unit_match=unit_match, unit_type=unit_type, unit_color=Color(unit_color) if unit_color else None, unit_attrs=unit_attrs, )
def __str__(self): return super().__str__()
[docs] def cutoff_text(self, limit: int) -> str: """ Cuts off text if it exceeds limit. Will NOT shorten the value, only suffix (if there is one). If there isn't enough space for just an ellipsis, it will try to shorten the label, so that the output will be 50/50 (label: value). :param limit: Maximum length of text :return: Shortened text """ return super()._cutoff_text(limit=limit)
# Typing alias AnyLabeledData = LabeledData.String | LabeledData.Number | LabeledData.Boolean | LabeledData.Path | LabeledData.Date \ | LabeledData.Bytes