File: console.py

package info (click to toggle)
openvswitch 3.5.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 97,848 kB
  • sloc: sh: 1,643,930; ansic: 313,386; python: 27,939; xml: 21,526; makefile: 546; javascript: 191
file content (193 lines) | stat: -rw-r--r-- 6,279 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# Copyright (c) 2023 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import colorsys
import itertools
import zlib

from rich.console import Console
from rich.color import Color
from rich.text import Text
from rich.style import Style

from ovs.flowviz.format import FlowFormatter, FlowBuffer


def file_header(name):
    return Text(f"### {name} ###")


class ConsoleBuffer(FlowBuffer):
    """ConsoleBuffer implements FlowBuffer to provide console-based text
    formatting based on rich.Text.

    Append functions accept a rich.Style.

    Args:
        rtext(rich.Text): Optional; text instance to reuse
    """

    def __init__(self, rtext):
        self._text = rtext or Text()

    @property
    def text(self):
        return self._text

    def _append(self, string, style):
        """Append to internal text."""
        return self._text.append(string, style)

    def append_key(self, kv, style):
        """Append a key.
        Args:
            kv (KeyValue): the KeyValue instance to append
            style (rich.Style): the style to use
        """
        return self._append(kv.meta.kstring, style)

    def append_delim(self, kv, style):
        """Append a delimiter.
        Args:
            kv (KeyValue): the KeyValue instance to append
            style (rich.Style): the style to use
        """
        return self._append(kv.meta.delim, style)

    def append_end_delim(self, kv, style):
        """Append an end delimiter.
        Args:
            kv (KeyValue): the KeyValue instance to append
            style (rich.Style): the style to use
        """
        return self._append(kv.meta.end_delim, style)

    def append_value(self, kv, style):
        """Append a value.
        Args:
            kv (KeyValue): the KeyValue instance to append
            style (rich.Style): the style to use
        """
        return self._append(kv.meta.vstring, style)

    def append_value_omitted(self, kv):
        """Append an omitted value.
        Args:
            kv (KeyValue): the KeyValue instance to append
        """
        dots = "." * len(kv.meta.vstring)
        return self._append(dots, None)

    def append_extra(self, extra, style):
        """Append extra string.
        Args:
            kv (KeyValue): the KeyValue instance to append
            style (rich.Style): the style to use
        """
        return self._append(extra, style)


class ConsoleFormatter(FlowFormatter):
    """ConsoleFormatter is a FlowFormatter that formats flows into the console
    using rich.Console.

    Args:
        console (rich.Console): Optional, an existing console to use
        max_value_len (int): Optional; max length of the printed values
        kwargs (dict): Optional; Extra arguments to be passed down to
            rich.console.Console()
    """

    def __init__(self, opts=None, console=None, **kwargs):
        super(ConsoleFormatter, self).__init__()
        self.style = self.style_from_opts(opts)
        self.console = console or Console(color_system="256", **kwargs)

    def style_from_opts(self, opts):
        return self._style_from_opts(opts, "console", Style)

    def print_flow(self, flow, highlighted=None, omitted=None):
        """Prints a flow to the console.

        Args:
            flow (ovs_dbg.OFPFlow): the flow to print
            style (dict): Optional; style dictionary to use
            highlighted (list): Optional; list of KeyValues to highlight
            omitted (list): Optional; list of KeyValues to omit
        """

        buf = ConsoleBuffer(Text())
        self.format_flow(buf, flow, highlighted, omitted)
        self.console.print(buf.text, soft_wrap=True)

    def format_flow(self, buf, flow, highlighted=None, omitted=None):
        """Formats the flow into the provided buffer as a rich.Text.

        Args:
            buf (FlowBuffer): the flow buffer to append to
            flow (ovs_dbg.OFPFlow): the flow to format
            style (FlowStyle): Optional; style object to use
            highlighted (list): Optional; list of KeyValues to highlight
            omitted (list): Optional; list of KeyValues to omit
        """
        return super(ConsoleFormatter, self).format_flow(
            buf, flow, self.style, highlighted, omitted
        )


def heat_pallete(min_value, max_value):
    """Generates a color pallete based on the 5-color heat pallete so that
    for each value between min and max a color is returned that represents it's
    relative size.
    Args:
        min_value (int): minimum value
        max_value (int) maximum value
    """
    h_min = 0  # red
    h_max = 220 / 360  # blue

    def heat(value):
        if max_value == min_value:
            r, g, b = colorsys.hsv_to_rgb(h_max / 2, 1.0, 1.0)
        else:
            normalized = (int(value) - min_value) / (max_value - min_value)
            hue = ((1 - normalized) + h_min) * (h_max - h_min)
            r, g, b = colorsys.hsv_to_rgb(hue, 1.0, 1.0)
        return Style(color=Color.from_rgb(r * 255, g * 255, b * 255))

    return heat


def hash_pallete(hue, saturation, value):
    """Generates a color pallete with the cartesian product
    of the hsv values provided and returns a callable that assigns a color for
    each value hash
    """
    HSV_tuples = itertools.product(hue, saturation, value)
    RGB_tuples = map(lambda x: colorsys.hsv_to_rgb(*x), HSV_tuples)
    styles = [
        Style(color=Color.from_rgb(r * 255, g * 255, b * 255))
        for r, g, b in RGB_tuples
    ]

    def get_style(string):
        hash_val = zlib.crc32(bytes(str(string), "utf-8"))
        return styles[hash_val % len(styles)]

    return get_style


def default_highlight():
    """Generates a default style for highlights."""
    return Style(underline=True)