Skip to content

pygx.formatting

String formatting primitives shared across PyGX.

formatting

String formatting primitives shared across PyGX.

pygx.formatting houses the Formattable mixin used by every symbolic value to produce its __str__ / __repr__ output, alongside helpers for bracket glyphs, key-value rendering, markdown-quoting, pluralization, and ANSI-coloring of terminal output. It sits below pygx.typing and pygx.symbolic in the dependency stack so those layers can rely on it without introducing cycles.

BracketType

Bases: IntEnum

Bracket types used for complex type formatting.

Formattable

Interface for classes whose instances can be pretty-formatted.

This interface overrides the default __repr__ and __str__ methods, routing both through pg.format so all Formattable objects print nicely and honor the pg.str_format / pg.repr_format scopes.

All symbolic types implement this interface.

format abstractmethod

format(
    compact: bool = False,
    verbose: bool = True,
    root_indent: int = 0,
    **kwargs: Any
) -> str

Formats this object into a string representation.

Parameters:

Name Type Description Default
compact bool

If True, this object will be formatted into a single line.

False
verbose bool

If True, this object will be formatted with verbosity. What verbose output includes is defined by each subclass.

True
root_indent int

The start indent level for this object if the output is a multi-line string.

0
**kwargs Any

Subclass specific keyword arguments.

{}

Returns:

Type Description
str

A string of formatted object.

Source code in pygx/formatting/_formatting.py
@abc.abstractmethod
def format(
    self,
    compact: bool = False,
    verbose: bool = True,
    root_indent: int = 0,
    **kwargs: Any,
) -> str:
    """Formats this object into a string representation.

    Args:
      compact: If True, this object will be formatted into a single line.
      verbose: If True, this object will be formatted with verbosity.
        What verbose output includes is defined by each subclass.
      root_indent: The start indent level for this object if the output is a
        multi-line string.
      **kwargs: Subclass specific keyword arguments.

    Returns:
      A string of formatted object.
    """

RawText

RawText(text: str)

Bases: Formattable

A string wrapper that formats verbatim, ignoring all format flags.

Source code in pygx/formatting/_formatting.py
def __init__(self, text: str):
    self.text = text

auto_plural

auto_plural(number: int, singular: str, plural: str | None = None) -> str

Returns the singular form if number is 1, otherwise the plural form.

Source code in pygx/formatting/_formatting.py
def auto_plural(number: int, singular: str, plural: str | None = None) -> str:
    """Returns the singular form if `number` is 1, otherwise the plural form."""
    if plural is None:
        plural = singular + 's'
    return singular if number == 1 else plural

bracket_chars

bracket_chars(bracket_type: BracketType) -> tuple[str, str]

Gets the (open, close) bracket characters for a bracket type.

Source code in pygx/formatting/_formatting.py
def bracket_chars(bracket_type: BracketType) -> tuple[str, str]:
    """Gets the (open, close) bracket characters for a bracket type."""
    return _BRACKET_CHARS[int(bracket_type)]

camel_to_snake

camel_to_snake(text: str, separator: str = '_') -> str

Returns the snake case version of a camel case string.

Source code in pygx/formatting/_formatting.py
def camel_to_snake(text: str, separator: str = '_') -> str:
    """Returns the snake case version of a camel case string."""
    chunks = []
    chunk_start = 0
    last_upper = 0
    length = len(text)
    for i, c in enumerate(text):
        if c.isupper():
            if last_upper < i - 1 or (i < length - 1 and text[i + 1].islower()):
                chunks.append(text[chunk_start:i])
                chunk_start = i
            last_upper = i
    chunks.append(text[chunk_start:])
    return (separator.join(c for c in chunks if c)).lower()

comma_delimited_str

comma_delimited_str(value_list: Sequence[Any]) -> str

Gets comma delimited string.

Source code in pygx/formatting/_formatting.py
def comma_delimited_str(value_list: Sequence[Any]) -> str:
    """Gets comma delimited string."""
    return ', '.join(str(quote_if_str(v)) for v in value_list)

format

format(
    value: Any,
    compact: bool = False,
    verbose: bool = True,
    root_indent: int = 0,
    list_wrap_threshold: int = 80,
    strip_object_id: bool = False,
    include_keys: set[str] | None = None,
    exclude_keys: set[str] | None = None,
    markdown: bool = False,
    max_str_len: int | None = None,
    max_bytes_len: int | None = None,
    *,
    custom_format: CustomFormatFn | None = None,
    memo: set[int] | None = None,
    **kwargs: Any
) -> str

Formats a (maybe) hierarchical value with flags.

Primitives are rendered via repr; lists, tuples and dicts are rendered recursively; Formattable values (all symbolic types) delegate to their own format method, which receives the flags below plus any extra keyword arguments.

Example:

class A(pg.Object):
  x: int = 1
  y: str = 'foo'

a = A(x=2)
# Multi-line (default).
assert pg.format(a) == "A(\n  x = 2,\n  y = 'foo'\n)"
# Single line.
assert pg.format(a, compact=True) == "A(x=2, y='foo')"
# Multi-line, Python-evaluable form (a flag understood by symbolic
# types): no spaces around '='.
assert pg.format(a, python_format=True) == "A(\n  x=2,\n  y='foo'\n)"
# Omit fields that equal their default value.
assert pg.format(a, compact=True, exclude_defaults=True) == 'A(x=2)'

Parameters:

Name Type Description Default
value Any

The value to format.

required
compact bool

If True, this object will be formatted into a single line.

False
verbose bool

If True, this object will be formatted with verbosity. What extra information verbose output includes is defined per Formattable subclass.

True
root_indent int

The start indent level for this object if the output is a multi-line string.

0
list_wrap_threshold int

A threshold in number of characters for wrapping a list value in a single line.

80
strip_object_id bool

If True, format object as '(...)' instead of 'object at

'.

False
include_keys set[str] | None

A set of keys to include from the top-level dict or object.

None
exclude_keys set[str] | None

A set of keys to exclude from the top-level dict or object. Applicable only when include_keys is set to None.

None
markdown bool

If True, quote the formatted value as markdown inline code or a code block. Applied only at the outermost level.

False
max_str_len int | None

The max length of the string to be formatted. If the string is longer than this length, it will be truncated.

None
max_bytes_len int | None

The max length of the bytes to be formatted. If the bytes is longer than this length, it will be truncated.

None
custom_format CustomFormatFn | None

An optional custom format function, which will be applied to value and each child value. If the function returns None, it will fall back to the default pg.format.

None
memo set[int] | None

A set of object ids that have been formatted. Used to avoid infinite recursion in the formatting process.

None
**kwargs Any

Keyword arguments that will be passed through unto child Formattable objects (e.g. python_format and exclude_defaults for symbolic values).

{}

Returns:

Type Description
str

A string representation for value.

Source code in pygx/formatting/_formatting.py
def format(  # pylint: disable=redefined-builtin
    value: Any,
    compact: bool = False,
    verbose: bool = True,
    root_indent: int = 0,
    list_wrap_threshold: int = 80,
    strip_object_id: bool = False,
    include_keys: set[str] | None = None,
    exclude_keys: set[str] | None = None,
    markdown: bool = False,
    max_str_len: int | None = None,
    max_bytes_len: int | None = None,
    *,
    custom_format: CustomFormatFn | None = None,
    memo: set[int] | None = None,
    **kwargs: Any,
) -> str:
    """Formats a (maybe) hierarchical value with flags.

    Primitives are rendered via `repr`; lists, tuples and dicts are rendered
    recursively; ``Formattable`` values (all symbolic types) delegate to their
    own ``format`` method, which receives the flags below plus any extra
    keyword arguments.

    **Example:**

    ```python
    class A(pg.Object):
      x: int = 1
      y: str = 'foo'

    a = A(x=2)
    # Multi-line (default).
    assert pg.format(a) == "A(\\n  x = 2,\\n  y = 'foo'\\n)"
    # Single line.
    assert pg.format(a, compact=True) == "A(x=2, y='foo')"
    # Multi-line, Python-evaluable form (a flag understood by symbolic
    # types): no spaces around '='.
    assert pg.format(a, python_format=True) == "A(\\n  x=2,\\n  y='foo'\\n)"
    # Omit fields that equal their default value.
    assert pg.format(a, compact=True, exclude_defaults=True) == 'A(x=2)'
    ```

    Args:
      value: The value to format.
      compact: If True, this object will be formatted into a single line.
      verbose: If True, this object will be formatted with verbosity. What
        extra information verbose output includes is defined per
        ``Formattable`` subclass.
      root_indent: The start indent level for this object if the output is a
        multi-line string.
      list_wrap_threshold: A threshold in number of characters for wrapping a
        list value in a single line.
      strip_object_id: If True, format object as '<class-name>(...)' instead
        of 'object at <address>'.
      include_keys: A set of keys to include from the top-level dict or object.
      exclude_keys: A set of keys to exclude from the top-level dict or object.
        Applicable only when `include_keys` is set to None.
      markdown: If True, quote the formatted value as markdown inline code or
        a code block. Applied only at the outermost level.
      max_str_len: The max length of the string to be formatted. If the string
        is longer than this length, it will be truncated.
      max_bytes_len: The max length of the bytes to be formatted. If the bytes
        is longer than this length, it will be truncated.
      custom_format: An optional custom format function, which will be applied
        to `value` and each child value. If the function returns None, it
        will fall back to the default `pg.format`.
      memo: A set of object ids that have been formatted. Used to avoid
        infinite recursion in the formatting process.
      **kwargs: Keyword arguments that will be passed through unto child
        ``Formattable`` objects (e.g. `python_format` and `exclude_defaults`
        for symbolic values).

    Returns:
      A string representation for `value`.
    """
    # 1) Custom format hook may intercept any value entirely.
    if custom_format is not None:
        result = custom_format(value, root_indent)
        if result is not None:
            return maybe_markdown_quote(result, markdown)

    # 2) Fast path: primitives can't recurse, so we skip memo / closures / TLS.
    #    Using `type(v) is X` instead of isinstance is intentional: it's faster
    #    and subclasses (e.g. `bool` of `int`) are handled by their own branch.
    value_type = type(value)
    if value_type is int or value_type is float or value_type is bool:
        return maybe_markdown_quote(repr(value), markdown)
    if value is None:
        return maybe_markdown_quote('None', markdown)
    if value_type is str:
        if max_str_len is not None and len(value) > max_str_len:
            value = value[:max_str_len] + '...'
        return maybe_markdown_quote(repr(value), markdown)
    if value_type is bytes:
        if max_bytes_len is not None and len(value) > max_bytes_len:
            value = value[:max_bytes_len] + b'...'
        return maybe_markdown_quote(repr(value), markdown)

    # 2b) Bound methods: render by name, never by expanding `__self__`.
    #     CPython's `<bound method C.m of {self!r}>` recurses forever when the
    #     owner holds the method back (directly, or via a contextual value that
    #     resolves to it) — and it escapes through Python's own `repr`, so the
    #     `memo` below never sees it. Once the owner is not expanded, a method
    #     cannot carry a cycle, so this returns before the memo bookkeeping.
    #     Plain functions, builtins and classes are left alone: their reprs are
    #     self-contained and already safe.
    if value_type is types.MethodType:
        return maybe_markdown_quote(_format_method(value), markdown)

    # 3) Cycle protection — only complex values need this.
    if memo is None:
        memo = set()
    id_ = id(value)
    if id_ in memo:
        return f'<recursive {value.__class__.__name__} at 0x{id_:x}>'
    memo.add(id_)

    # 4) Dispatch on container/Formattable type.
    is_formattable = _is_formattable(value_type)

    # Downstream `Formattable.format()` implementations expect `exclude_keys`
    # to be a non-None set when they pop it from kwargs and mutate it
    # (e.g. to add their own field names). Preserve that invariant.
    if exclude_keys is None:
        exclude_keys = set()

    # `markdown` is only applied at the outer-most level, so we suppress it for
    # any nested `__str__`/`__repr__` invocations. The TLS push is only needed
    # for branches that may call those: the Formattable branch (calls into
    # `value.format()` which often uses `str()`/`repr()` internally) and the
    # generic "other" branch (calls `str_ext`/`repr_ext` directly). List, tuple,
    # and dict branches recurse via `format()` which uses `markdown=False` by
    # default, so the push there would be pure overhead.
    try:
        # Hot path: Formattable (covers pg.Object/pg.Dict/pg.List etc.) —
        # delegates to `value.format()` which handles its own children. No
        # `child_kwargs` dict needed; the central kwargs are passed through
        # directly. Downstream tolerates `exclude_keys=None`, so we don't
        # allocate an empty set here.
        if is_formattable:
            if _outer_markdown_active():
                with str_format(markdown=False), repr_format(markdown=False):
                    s = value.format(
                        compact=compact,
                        verbose=verbose,
                        root_indent=root_indent,
                        list_wrap_threshold=list_wrap_threshold,
                        strip_object_id=strip_object_id,
                        include_keys=include_keys,
                        exclude_keys=exclude_keys,
                        max_str_len=max_str_len,
                        max_bytes_len=max_bytes_len,
                        custom_format=custom_format,
                        memo=memo,
                        **kwargs,
                    )
            else:
                s = value.format(
                    compact=compact,
                    verbose=verbose,
                    root_indent=root_indent,
                    list_wrap_threshold=list_wrap_threshold,
                    strip_object_id=strip_object_id,
                    include_keys=include_keys,
                    exclude_keys=exclude_keys,
                    max_str_len=max_str_len,
                    max_bytes_len=max_bytes_len,
                    custom_format=custom_format,
                    memo=memo,
                    **kwargs,
                )
        else:
            is_list = value_type is list or isinstance(value, list)
            is_tuple = not is_list and (
                value_type is tuple or isinstance(value, tuple)
            )
            is_dict = (
                not is_list
                and not is_tuple
                and (value_type is dict or isinstance(value, dict))
            )

            if is_list or is_tuple or is_dict:
                # Shared kwargs for recursive child formatting. `markdown` is
                # intentionally not propagated — it only applies at the
                # outer-most level.
                child_kwargs = dict(
                    compact=compact,
                    verbose=verbose,
                    root_indent=root_indent + 1,
                    list_wrap_threshold=list_wrap_threshold,
                    strip_object_id=strip_object_id,
                    max_str_len=max_str_len,
                    max_bytes_len=max_bytes_len,
                    custom_format=custom_format,
                    memo=memo,
                    **kwargs,
                )
                if is_list:
                    s = _format_sequence(
                        value,
                        '[',
                        ']',
                        compact,
                        list_wrap_threshold,
                        root_indent,
                        child_kwargs,
                    )
                elif is_tuple:
                    s = _format_sequence(
                        value,
                        '(',
                        ')',
                        compact,
                        list_wrap_threshold,
                        root_indent,
                        child_kwargs,
                    )
                else:
                    s = _format_dict(
                        value,
                        compact,
                        root_indent,
                        include_keys,
                        exclude_keys,
                        child_kwargs,
                    )
            else:
                # Generic "other" path — may call user `__str__`/`__repr__`.
                if _outer_markdown_active():
                    with (
                        str_format(markdown=False),
                        repr_format(markdown=False),
                    ):
                        s = _format_other(
                            value,
                            compact,
                            strip_object_id,
                            custom_format,
                            root_indent,
                        )
                else:
                    s = _format_other(
                        value,
                        compact,
                        strip_object_id,
                        custom_format,
                        root_indent,
                    )
    finally:
        memo.discard(id_)
    return maybe_markdown_quote(s, markdown)

kvlist_str

kvlist_str(
    kvlist: list[tuple[str, Any, Any]],
    compact: bool = True,
    verbose: bool = False,
    root_indent: int = 0,
    *,
    label: str | None = None,
    bracket_type: BracketType = ROUND,
    custom_format: CustomFormatFn | None = None,
    memo: set[int] | None = None,
    **kwargs: Any
) -> str

Formats a list of key/value pairs into a comma-delimited string.

Pairs whose value equals their default value are omitted. This is the workhorse behind most Formattable.format implementations.

Example:

assert pg.formatting.kvlist_str(
    [
        ('x', 1, None),      # Included: 1 != None.
        ('y', 'foo', 'foo'), # Omitted: value equals the default.
    ],
    label='Point',
) == "Point(x=1)"

Parameters:

Name Type Description Default
kvlist list[tuple[str, Any, Any]]

List of tuples in format of (key, value, default_value or a tuple of default values). A pair is omitted when its value equals the default (or any of the defaults).

required
compact bool

If True, format each value in kvlist in compact form.

True
verbose bool

If True, format each value in kvlist in verbose form.

False
root_indent int

The indent to apply to values in kvlist if they are multi-line.

0
label str | None

(Optional) If not None, add label to brace all kv pairs.

None
bracket_type BracketType

Bracket type used for embracing the kv pairs. Applicable only when label is not None.

ROUND
custom_format CustomFormatFn | None

An optional custom format function, which will be applied to each value (and child values) in kvlist. If the function returns None, it will fall back to the default pg.format.

None
memo set[int] | None

A set of object ids that have been formatted. Used to avoid infinite recursion in the formatting process.

None
**kwargs Any

Keyword arguments that will be passed through unto child Formattable objects.

{}

Returns:

Type Description
str

A formatted string from a list of key/value pairs delimited by comma.

Source code in pygx/formatting/_formatting.py
def kvlist_str(
    kvlist: list[tuple[str, Any, Any]],
    compact: bool = True,
    verbose: bool = False,
    root_indent: int = 0,
    *,
    label: str | None = None,
    bracket_type: BracketType = BracketType.ROUND,
    custom_format: CustomFormatFn | None = None,
    memo: set[int] | None = None,
    **kwargs: Any,
) -> str:
    """Formats a list of key/value pairs into a comma-delimited string.

    Pairs whose value equals their default value are omitted. This is the
    workhorse behind most ``Formattable.format`` implementations.

    **Example:**

    ```python
    assert pg.formatting.kvlist_str(
        [
            ('x', 1, None),      # Included: 1 != None.
            ('y', 'foo', 'foo'), # Omitted: value equals the default.
        ],
        label='Point',
    ) == "Point(x=1)"
    ```

    Args:
      kvlist: List of tuples in format of
        (key, value, default_value or a tuple of default values). A pair is
        omitted when its value equals the default (or any of the defaults).
      compact: If True, format each value in kvlist in compact form.
      verbose: If True, format each value in kvlist in verbose form.
      root_indent: The indent to apply to values in kvlist if they are
        multi-line.
      label: (Optional) If not None, add label to brace all kv pairs.
      bracket_type: Bracket type used for embracing the kv pairs. Applicable
        only when `label` is not None.
      custom_format: An optional custom format function, which will be applied
        to each value (and child values) in kvlist. If the function returns
        None, it will fall back to the default `pg.format`.
      memo: A set of object ids that have been formatted. Used to avoid
        infinite recursion in the formatting process.
      **kwargs: Keyword arguments that will be passed through unto child
        ``Formattable`` objects.

    Returns:
      A formatted string from a list of key/value pairs delimited by comma.
    """
    # Build the body as a list of fragments and join once at the end —
    # significantly faster than io.StringIO writes for the small-N case that
    # dominates `Formattable.format()` callers.
    body: list[str] = []
    child_indent = (root_indent + 1) if label else root_indent
    child_indent_str = '  ' * child_indent if not compact else ''
    separator = ', ' if compact else ',\n'
    has_content = False

    for k, v, d in kvlist:
        if isinstance(d, tuple):
            include_pair = True
            for sd in d:
                if sd == v:
                    include_pair = False
                    break
        else:
            include_pair = v != d
        if not include_pair:
            continue
        if has_content:
            body.append(separator)
        if not compact:
            body.append(child_indent_str)
        formatted = format(
            v,
            compact=compact,
            verbose=verbose,
            root_indent=child_indent,
            custom_format=custom_format,
            memo=memo,
            **kwargs,
        )
        if k:
            body.append(k)
            body.append('=')
        body.append(str_ext(formatted, custom_format, child_indent))
        has_content = True

    if label is None:
        return ''.join(body)
    bracket_start, bracket_end = bracket_chars(bracket_type)
    if not has_content:
        # Empty: "Label()".
        return f'{label}{bracket_start}{bracket_end}'
    if compact:
        return f'{label}{bracket_start}{"".join(body)}{bracket_end}'
    # Multi-line with label: "Label(\n  ...\n)".
    return (
        f'{label}{bracket_start}\n{"".join(body)}\n'
        f'{"  " * root_indent}{bracket_end}'
    )

maybe_markdown_quote

maybe_markdown_quote(s: str, markdown: bool = True) -> str

Quotes s as markdown when markdown is True.

Single-line strings become inline code; multi-line strings become a fenced code block.

Source code in pygx/formatting/_formatting.py
def maybe_markdown_quote(s: str, markdown: bool = True) -> str:
    """Quotes `s` as markdown when `markdown` is True.

    Single-line strings become inline code; multi-line strings become a
    fenced code block.
    """
    if not markdown:
        return s
    if '\n' not in s:
        return f'`{s}`'
    else:
        return f'```\n{s}\n```'

printv

printv(*args, **kwargs)

Prints values formatted with pg.format (exposed as pg.print).

Each positional argument is formatted with pg.format using the given keyword arguments; file (default sys.stdout) is passed through to the builtin print.

Source code in pygx/formatting/_formatting.py
def printv(*args, **kwargs):
    """Prints values formatted with `pg.format` (exposed as ``pg.print``).

    Each positional argument is formatted with `pg.format` using the given
    keyword arguments; `file` (default ``sys.stdout``) is passed through to
    the builtin ``print``.
    """
    fs = kwargs.pop('file', sys.stdout)
    print(*[format(v, **kwargs) for v in args], file=fs)

quote_if_str

quote_if_str(value: Any) -> Any

Quotes the value if it is a str.

Source code in pygx/formatting/_formatting.py
def quote_if_str(value: Any) -> Any:
    """Quotes the value if it is a str."""
    if isinstance(value, str):
        return repr(value)
    return value

repr_format

repr_format(**kwargs) -> ContextManager[dict[str, Any]]

Context manager overriding the format kwargs used by __repr__.

The __repr__ counterpart of pg.str_format.

Source code in pygx/formatting/_formatting.py
def repr_format(**kwargs) -> ContextManager[dict[str, Any]]:
    """Context manager overriding the format kwargs used by ``__repr__``.

    The ``__repr__`` counterpart of `pg.str_format`.
    """
    return thread_local.thread_local_arg_scope(
        _TLS_REPR_FORMAT_KWARGS, **kwargs
    )

str_format

str_format(**kwargs) -> ContextManager[dict[str, Any]]

Context manager overriding the format kwargs used by __str__.

Within the scope, str() on any Formattable object applies the given pg.format kwargs on top of the object's own defaults.

Example:

class A(pg.Object):
  x: int = 1

with pg.str_format(compact=True):
  assert str(A()) == 'A(x=1)'
Source code in pygx/formatting/_formatting.py
def str_format(**kwargs) -> ContextManager[dict[str, Any]]:
    """Context manager overriding the format kwargs used by ``__str__``.

    Within the scope, `str()` on any ``Formattable`` object applies the
    given `pg.format` kwargs on top of the object's own defaults.

    **Example:**

    ```python
    class A(pg.Object):
      x: int = 1

    with pg.str_format(compact=True):
      assert str(A()) == 'A(x=1)'
    ```
    """
    return thread_local.thread_local_arg_scope(_TLS_STR_FORMAT_KWARGS, **kwargs)

colored

colored(
    text: str,
    color: str | None = None,
    background: str | None = None,
    styles: list[str] | None = None,
) -> str

Returns the colored text with ANSI color characters.

Coloring requires the optional termcolor package; when it is not installed, text is returned unchanged.

Parameters:

Name Type Description Default
text str

A string that may or may not already have ANSI color characters.

required
color str | None

A string for text colors. Applicable values are: 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'.

None
background str | None

A string for background colors. Applicable values are: 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'.

None
styles list[str] | None

A list of strings for applying styles on the text. Applicable values are: 'bold', 'dark', 'underline', 'blink', 'reverse', 'concealed'.

None

Returns:

Type Description
str

A string with ANSI color characters embracing the entire text.

Source code in pygx/formatting/_text_color.py
def colored(
    text: str,
    color: str | None = None,
    background: str | None = None,
    styles: list[str] | None = None,
) -> str:
    """Returns the colored text with ANSI color characters.

    Coloring requires the optional ``termcolor`` package; when it is not
    installed, `text` is returned unchanged.

    Args:
      text: A string that may or may not already have ANSI color characters.
      color: A string for text colors. Applicable values are:
        'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'.
      background: A string for background colors. Applicable values are:
        'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'.
      styles: A list of strings for applying styles on the text.
        Applicable values are:
        'bold', 'dark', 'underline', 'blink', 'reverse', 'concealed'.

    Returns:
      A string with ANSI color characters embracing the entire text.
    """
    if not _termcolor_loaded:
        _load_termcolor()
    if not termcolor:
        return text
    return termcolor.colored(
        text,
        color=color,
        on_color=('on_' + background) if background else None,
        attrs=styles,
    )

colored_block

colored_block(
    text: str,
    block_start: str,
    block_end: str,
    color: str | None = None,
    background: str | None = None,
    styles: list[str] | None = None,
) -> str

Applies colors to the text blocks delimited by markers.

Parameters:

Name Type Description Default
text str

A string that may or may not already have ANSI color characters.

required
block_start str

A string that signals the start of a block. E.g. '{{'.

required
block_end str

A string that signals the end of a block. E.g. '}}'.

required
color str | None

A string for text colors. Applicable values are: 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'.

None
background str | None

A string for background colors. Applicable values are: 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'.

None
styles list[str] | None

A list of strings for applying styles on the text. Applicable values are: 'bold', 'dark', 'underline', 'blink', 'reverse', 'concealed'.

None

Returns:

Type Description
str

A string with ANSI color characters embracing the matched text blocks.

Source code in pygx/formatting/_text_color.py
def colored_block(
    text: str,
    block_start: str,
    block_end: str,
    color: str | None = None,
    background: str | None = None,
    styles: list[str] | None = None,
) -> str:
    """Applies colors to the text blocks delimited by markers.

    Args:
      text: A string that may or may not already have ANSI color characters.
      block_start: A string that signals the start of a block. E.g. '{{'.
      block_end: A string that signals the end of a block. E.g. '}}'.
      color: A string for text colors. Applicable values are:
        'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'.
      background: A string for background colors. Applicable values are:
        'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'.
      styles: A list of strings for applying styles on the text.
        Applicable values are:
        'bold', 'dark', 'underline', 'blink', 'reverse', 'concealed'.

    Returns:
      A string with ANSI color characters embracing the matched text blocks.
    """
    if not color and not background and not styles:
        return text

    s = []
    end_index = 0
    previous_color = None

    def write_nonblock_text(text: str, previous_color: str | None):
        if previous_color:
            s.append(previous_color)
        s.append(text)

    while True:
        start_index = text.find(block_start, end_index)
        if start_index == -1:
            write_nonblock_text(text[end_index:], previous_color)
            break

        # Deal with text since last block.
        since_last_block = text[end_index:start_index]
        write_nonblock_text(since_last_block, previous_color)
        colors = re.findall(_ANSI_COLOR_REGEX, since_last_block)
        if colors:
            previous_color = colors[-1]

        # Match block.
        end_index = text.find(block_end, start_index + len(block_start))
        if end_index == -1:
            write_nonblock_text(text[start_index:], previous_color)
            break
        end_index += len(block_end)

        # Write block text.
        block = text[start_index:end_index]
        block = colored(
            block, color=color, background=background, styles=styles
        )
        s.append(block)
    return ''.join(s)

decolor

decolor(text: str) -> str

Removes ANSI color characters from a string.

Source code in pygx/formatting/_text_color.py
def decolor(text: str) -> str:
    """Removes ANSI color characters from a string."""
    return re.sub(_ANSI_COLOR_REGEX, '', text)

options: show_root_heading: false show_root_toc_entry: false members_order: source heading_level: 2