pytermgui.prettifiers

This module provides some methods to prettify things.

The main export here is prettify. It uses pytermgui.parser.tim, and all of its markup magic to create prettier representations of whatever is given.

  1"""This module provides some methods to prettify things.
  2
  3The main export here is `prettify`. It uses `pytermgui.parser.tim`, and all of its
  4markup magic to create prettier representations of whatever is given.
  5"""
  6
  7from __future__ import annotations
  8
  9from collections import UserDict, UserList
 10from typing import Any
 11
 12from .exceptions import MarkupSyntaxError
 13from .fancy_repr import build_fancy_repr, supports_fancy_repr
 14from .highlighters import highlight_python, highlight_tim
 15from .markup import tim
 16from .regex import RE_ANSI, RE_MARKUP
 17
 18__all__ = ["prettify"]
 19
 20CONTAINER_TYPES = (list, dict, set, tuple, UserDict, UserList)
 21
 22
 23# Note: This function can be optimized in a lot of ways, primarily the way containers
 24#       are treated.
 25def prettify(  # pylint: disable=too-many-branches
 26    target: Any,
 27    indent: int = 2,
 28    force_markup: bool = False,
 29    expand_all: bool = False,
 30    parse: bool = True,
 31) -> str:
 32    """Prettifies any Python object.
 33
 34    This uses a set of pre-defined aliases for the styling, and as such is fully
 35    customizable.
 36
 37    The aliases are:
 38    - `str`: Applied to all strings, so long as they do not contain TIM code.
 39    - `int`: Applied to all integers and booleans. The latter are included as they
 40        subclass int.
 41    - `type`: Applied to all types.
 42    - `none`: Applied to NoneType. Note that when using `pytermgui.pretty`, a
 43        single `None` return value will not be printed, only when part of a more
 44        complex structure.
 45
 46    Args:
 47        target: The object to prettify. Can be any type.
 48        indent: The indentation used for multi-line objects, like containers. When
 49            set to 0, these will be collapsed. By default, container types with
 50            `len() == 1` are always collapsed, regardless of this value. See
 51            `expand_all` to overwrite that behaviour.
 52        force_markup: When this is set every ANSI-sequence string will be turned
 53            into markup and syntax highlighted.
 54        expand_all: When set, objects that would normally be force-collapsed are
 55            also going to be expanded.
 56        parse: If not set, the return value will be a plain markup string, not yet
 57            parsed.
 58
 59    Returns:
 60        A pretty string of the given target.
 61    """
 62
 63    if isinstance(target, str):
 64        if RE_MARKUP.match(target) is not None:
 65            try:
 66                highlighted_target = highlight_tim(target)
 67
 68                if parse:
 69                    return f'"{tim.parse(highlighted_target)}"'
 70
 71                return highlighted_target + "[/]"
 72
 73            except MarkupSyntaxError:
 74                pass
 75
 76        if RE_ANSI.match(target) is not None:
 77            return target + "\x1b[0m"
 78
 79        target = repr(target)
 80
 81    if isinstance(target, CONTAINER_TYPES):
 82        if len(target) < 2 and not expand_all:
 83            indent = 0
 84
 85        indent_str = ("\n" if indent > 0 else "") + indent * " "
 86
 87        chars = str(target)[0], str(target)[-1]
 88        buff = chars[0]
 89
 90        if isinstance(target, (dict, UserDict)):
 91            for i, (key, value) in enumerate(target.items()):
 92                if i > 0:
 93                    buff += ", "
 94
 95                buff += indent_str + highlight_python(f"{key!r}: ")
 96
 97                pretty = prettify(
 98                    value,
 99                    indent=indent,
100                    expand_all=expand_all,
101                    force_markup=force_markup,
102                    parse=False,
103                )
104
105                lines = pretty.splitlines()
106                buff += lines[0]
107
108                for line in lines[1:]:
109                    buff += indent_str + line
110
111        else:
112            for i, value in enumerate(target):
113                if i > 0:
114                    buff += ", "
115
116                pretty = prettify(
117                    value,
118                    indent=indent,
119                    expand_all=expand_all,
120                    force_markup=force_markup,
121                    parse=False,
122                )
123
124                lines = pretty.splitlines()
125
126                for line in lines:
127                    buff += indent_str + line
128
129        if indent > 0:
130            buff += "\n"
131
132        buff += chars[1]
133
134        if force_markup:
135            return buff
136
137        return tim.parse(buff)
138
139    if supports_fancy_repr(target):
140        buff = build_fancy_repr(target)
141
142    else:
143        buff = highlight_python(str(target))
144
145    return tim.parse(buff) if parse else buff
def prettify( target: Any, indent: int = 2, force_markup: bool = False, expand_all: bool = False, parse: bool = True) -> str:
 26def prettify(  # pylint: disable=too-many-branches
 27    target: Any,
 28    indent: int = 2,
 29    force_markup: bool = False,
 30    expand_all: bool = False,
 31    parse: bool = True,
 32) -> str:
 33    """Prettifies any Python object.
 34
 35    This uses a set of pre-defined aliases for the styling, and as such is fully
 36    customizable.
 37
 38    The aliases are:
 39    - `str`: Applied to all strings, so long as they do not contain TIM code.
 40    - `int`: Applied to all integers and booleans. The latter are included as they
 41        subclass int.
 42    - `type`: Applied to all types.
 43    - `none`: Applied to NoneType. Note that when using `pytermgui.pretty`, a
 44        single `None` return value will not be printed, only when part of a more
 45        complex structure.
 46
 47    Args:
 48        target: The object to prettify. Can be any type.
 49        indent: The indentation used for multi-line objects, like containers. When
 50            set to 0, these will be collapsed. By default, container types with
 51            `len() == 1` are always collapsed, regardless of this value. See
 52            `expand_all` to overwrite that behaviour.
 53        force_markup: When this is set every ANSI-sequence string will be turned
 54            into markup and syntax highlighted.
 55        expand_all: When set, objects that would normally be force-collapsed are
 56            also going to be expanded.
 57        parse: If not set, the return value will be a plain markup string, not yet
 58            parsed.
 59
 60    Returns:
 61        A pretty string of the given target.
 62    """
 63
 64    if isinstance(target, str):
 65        if RE_MARKUP.match(target) is not None:
 66            try:
 67                highlighted_target = highlight_tim(target)
 68
 69                if parse:
 70                    return f'"{tim.parse(highlighted_target)}"'
 71
 72                return highlighted_target + "[/]"
 73
 74            except MarkupSyntaxError:
 75                pass
 76
 77        if RE_ANSI.match(target) is not None:
 78            return target + "\x1b[0m"
 79
 80        target = repr(target)
 81
 82    if isinstance(target, CONTAINER_TYPES):
 83        if len(target) < 2 and not expand_all:
 84            indent = 0
 85
 86        indent_str = ("\n" if indent > 0 else "") + indent * " "
 87
 88        chars = str(target)[0], str(target)[-1]
 89        buff = chars[0]
 90
 91        if isinstance(target, (dict, UserDict)):
 92            for i, (key, value) in enumerate(target.items()):
 93                if i > 0:
 94                    buff += ", "
 95
 96                buff += indent_str + highlight_python(f"{key!r}: ")
 97
 98                pretty = prettify(
 99                    value,
100                    indent=indent,
101                    expand_all=expand_all,
102                    force_markup=force_markup,
103                    parse=False,
104                )
105
106                lines = pretty.splitlines()
107                buff += lines[0]
108
109                for line in lines[1:]:
110                    buff += indent_str + line
111
112        else:
113            for i, value in enumerate(target):
114                if i > 0:
115                    buff += ", "
116
117                pretty = prettify(
118                    value,
119                    indent=indent,
120                    expand_all=expand_all,
121                    force_markup=force_markup,
122                    parse=False,
123                )
124
125                lines = pretty.splitlines()
126
127                for line in lines:
128                    buff += indent_str + line
129
130        if indent > 0:
131            buff += "\n"
132
133        buff += chars[1]
134
135        if force_markup:
136            return buff
137
138        return tim.parse(buff)
139
140    if supports_fancy_repr(target):
141        buff = build_fancy_repr(target)
142
143    else:
144        buff = highlight_python(str(target))
145
146    return tim.parse(buff) if parse else buff

Prettifies any Python object.

This uses a set of pre-defined aliases for the styling, and as such is fully customizable.

The aliases are:

  • str: Applied to all strings, so long as they do not contain TIM code.
  • int: Applied to all integers and booleans. The latter are included as they subclass int.
  • type: Applied to all types.
  • none: Applied to NoneType. Note that when using pytermgui.pretty, a single None return value will not be printed, only when part of a more complex structure.
Args
  • target: The object to prettify. Can be any type.
  • indent: The indentation used for multi-line objects, like containers. When set to 0, these will be collapsed. By default, container types with len() == 1 are always collapsed, regardless of this value. See expand_all to overwrite that behaviour.
  • force_markup: When this is set every ANSI-sequence string will be turned into markup and syntax highlighted.
  • expand_all: When set, objects that would normally be force-collapsed are also going to be expanded.
  • parse: If not set, the return value will be a plain markup string, not yet parsed.
Returns

A pretty string of the given target.