Plain is headed towards 1.0! Subscribe for development updates →

 1from collections import namedtuple
 2
 3Message = namedtuple("Message", "type data time name color")
 4
 5
 6class Printer:
 7    """
 8    Printer is where Poncho's user-visible output is defined. A Printer
 9    instance receives typed messages and prints them to its output (usually
10    STDOUT) in the Poncho format.
11    """
12
13    def __init__(
14        self,
15        print_func,
16        time_format="%H:%M:%S",
17        width=0,
18        color=True,
19        prefix=True,
20    ):
21        self.print_func = print_func
22        self.time_format = time_format
23        self.width = width
24        self.color = color
25        self.prefix = prefix
26
27    def write(self, message):
28        if message.type != "line":
29            raise RuntimeError('Printer can only process messages of type "line"')
30
31        name = message.name if message.name is not None else ""
32        name = name.ljust(self.width)
33        if name:
34            name += " "
35
36        # When encountering data that cannot be interpreted as UTF-8 encoded
37        # Unicode, Printer will replace the unrecognisable bytes with the
38        # Unicode replacement character (U+FFFD).
39        if isinstance(message.data, bytes):
40            string = message.data.decode("utf-8", "replace")
41        else:
42            string = message.data
43
44        for line in string.splitlines():
45            prefix = ""
46            if self.prefix:
47                time_formatted = message.time.strftime(self.time_format)
48                prefix = f"{time_formatted} {name}| "
49                if self.color and message.color:
50                    prefix = _color_string(message.color, prefix)
51
52            self.print_func(prefix + line)
53
54
55def _color_string(color, s):
56    def _ansi(code):
57        return f"\033[{code}m"
58
59    return f"{_ansi(0)}{_ansi(color)}{s}{_ansi(0)}"