pytermgui.fancy_repr

The __fancy_repl__ protocol.

 1"""The `__fancy_repl__` protocol."""
 2
 3from __future__ import annotations
 4
 5from typing import Dict, Generator, Protocol, Union
 6
 7from .highlighters import highlight_python
 8
 9FancyYield = Union[str, Dict[str, Union[str, bool]]]
10
11__all__ = [
12    "SupportsFancyRepr",
13    "supports_fancy_repr",
14    "build_fancy_repr",
15]
16
17
18class SupportsFancyRepr(Protocol):  # pylint: disable=too-few-public-methods
19    """An object that supports the `__fancy_repr__` dunder."""
20
21    def __fancy_repr__(self) -> Generator[FancyYield, None, None]:
22        """Yields some fancy text.
23
24        Each value yielded can be one of two types. If a dictionary is yielded,
25        it will be assumed to have `text` and `highlight` fields. `text` will be
26        the string included in the repr, and `highlight` will be a boolean describing
27        whether the part should be highlighted. At the moment highlighting is done by
28        `highlight_python`, but this might be configurable once more highlighters are
29        available.
30
31        If a `str` is yielded, it is assumed to be a shorthand for:
32
33            {"text": <your_text>, "highlight": True}
34        """
35
36
37def supports_fancy_repr(obj: object) -> bool:
38    """Determines whether the given object supports the fancy repl protocol."""
39
40    return hasattr(obj, "__fancy_repr__") and not isinstance(obj, type)
41
42
43def build_fancy_repr(obj: SupportsFancyRepr) -> str:
44    """Interprets objects with the `__fancy_repr__` protocol."""
45
46    output = ""
47    for item in obj.__fancy_repr__():
48        if isinstance(item, str):
49            output += highlight_python(item)
50            continue
51
52        text = item["text"]
53        assert isinstance(text, str)
54
55        highlight = item["highlight"]
56
57        if highlight:
58            text = highlight_python(text)
59
60        output += text
61
62    return output
class SupportsFancyRepr(typing.Protocol):
19class SupportsFancyRepr(Protocol):  # pylint: disable=too-few-public-methods
20    """An object that supports the `__fancy_repr__` dunder."""
21
22    def __fancy_repr__(self) -> Generator[FancyYield, None, None]:
23        """Yields some fancy text.
24
25        Each value yielded can be one of two types. If a dictionary is yielded,
26        it will be assumed to have `text` and `highlight` fields. `text` will be
27        the string included in the repr, and `highlight` will be a boolean describing
28        whether the part should be highlighted. At the moment highlighting is done by
29        `highlight_python`, but this might be configurable once more highlighters are
30        available.
31
32        If a `str` is yielded, it is assumed to be a shorthand for:
33
34            {"text": <your_text>, "highlight": True}
35        """

An object that supports the __fancy_repr__ dunder.

SupportsFancyRepr(*args, **kwargs)
1430def _no_init_or_replace_init(self, *args, **kwargs):
1431    cls = type(self)
1432
1433    if cls._is_protocol:
1434        raise TypeError('Protocols cannot be instantiated')
1435
1436    # Already using a custom `__init__`. No need to calculate correct
1437    # `__init__` to call. This can lead to RecursionError. See bpo-45121.
1438    if cls.__init__ is not _no_init_or_replace_init:
1439        return
1440
1441    # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1442    # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1443    # searches for a proper new `__init__` in the MRO. The new `__init__`
1444    # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1445    # instantiation of the protocol subclass will thus use the new
1446    # `__init__` and no longer call `_no_init_or_replace_init`.
1447    for base in cls.__mro__:
1448        init = base.__dict__.get('__init__', _no_init_or_replace_init)
1449        if init is not _no_init_or_replace_init:
1450            cls.__init__ = init
1451            break
1452    else:
1453        # should not happen
1454        cls.__init__ = object.__init__
1455
1456    cls.__init__(self, *args, **kwargs)
def supports_fancy_repr(obj: object) -> bool:
38def supports_fancy_repr(obj: object) -> bool:
39    """Determines whether the given object supports the fancy repl protocol."""
40
41    return hasattr(obj, "__fancy_repr__") and not isinstance(obj, type)

Determines whether the given object supports the fancy repl protocol.

def build_fancy_repr(obj: pytermgui.fancy_repr.SupportsFancyRepr) -> str:
44def build_fancy_repr(obj: SupportsFancyRepr) -> str:
45    """Interprets objects with the `__fancy_repr__` protocol."""
46
47    output = ""
48    for item in obj.__fancy_repr__():
49        if isinstance(item, str):
50            output += highlight_python(item)
51            continue
52
53        text = item["text"]
54        assert isinstance(text, str)
55
56        highlight = item["highlight"]
57
58        if highlight:
59            text = highlight_python(text)
60
61        output += text
62
63    return output

Interprets objects with the __fancy_repr__ protocol.