hexlogger 2.0.2__tar.gz → 2.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hexlogger-2.0.2 → hexlogger-2.0.3}/PKG-INFO +1 -1
- {hexlogger-2.0.2 → hexlogger-2.0.3}/hexlogger/__init__.py +1 -1
- {hexlogger-2.0.2 → hexlogger-2.0.3}/hexlogger/core.py +7 -14
- {hexlogger-2.0.2 → hexlogger-2.0.3}/hexlogger/formatting.py +28 -15
- {hexlogger-2.0.2 → hexlogger-2.0.3}/hexlogger/progress.py +17 -9
- hexlogger-2.0.3/hexlogger/utils.py +74 -0
- {hexlogger-2.0.2 → hexlogger-2.0.3}/hexlogger/widgets.py +25 -15
- {hexlogger-2.0.2 → hexlogger-2.0.3}/hexlogger.egg-info/PKG-INFO +1 -1
- {hexlogger-2.0.2 → hexlogger-2.0.3}/pyproject.toml +1 -1
- hexlogger-2.0.2/hexlogger/utils.py +0 -30
- {hexlogger-2.0.2 → hexlogger-2.0.3}/LICENSE +0 -0
- {hexlogger-2.0.2 → hexlogger-2.0.3}/README.md +0 -0
- {hexlogger-2.0.2 → hexlogger-2.0.3}/hexlogger/_compat.py +0 -0
- {hexlogger-2.0.2 → hexlogger-2.0.3}/hexlogger/colors.py +0 -0
- {hexlogger-2.0.2 → hexlogger-2.0.3}/hexlogger/config.py +0 -0
- {hexlogger-2.0.2 → hexlogger-2.0.3}/hexlogger/gradient.py +0 -0
- {hexlogger-2.0.2 → hexlogger-2.0.3}/hexlogger/styles.py +0 -0
- {hexlogger-2.0.2 → hexlogger-2.0.3}/hexlogger/themes.py +0 -0
- {hexlogger-2.0.2 → hexlogger-2.0.3}/hexlogger.egg-info/SOURCES.txt +0 -0
- {hexlogger-2.0.2 → hexlogger-2.0.3}/hexlogger.egg-info/dependency_links.txt +0 -0
- {hexlogger-2.0.2 → hexlogger-2.0.3}/hexlogger.egg-info/top_level.txt +0 -0
- {hexlogger-2.0.2 → hexlogger-2.0.3}/setup.cfg +0 -0
|
@@ -14,16 +14,6 @@ def _get_time():
|
|
|
14
14
|
return ""
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
def _write_to_file(message):
|
|
18
|
-
cfg = get_config()
|
|
19
|
-
if cfg._file_handle:
|
|
20
|
-
try:
|
|
21
|
-
cfg._file_handle.write(strip_ansi(message) + "\n")
|
|
22
|
-
cfg._file_handle.flush()
|
|
23
|
-
except Exception:
|
|
24
|
-
pass
|
|
25
|
-
|
|
26
|
-
|
|
27
17
|
def _log(level, message, level_enum):
|
|
28
18
|
try:
|
|
29
19
|
cfg = get_config()
|
|
@@ -31,13 +21,16 @@ def _log(level, message, level_enum):
|
|
|
31
21
|
return
|
|
32
22
|
t = cfg.theme
|
|
33
23
|
now = _get_time()
|
|
34
|
-
level_color = t.get(level)
|
|
35
|
-
level_label = t.get(f"label_{level}")
|
|
36
24
|
style_fn = STYLES.get(cfg.style, STYLES["default"])
|
|
37
|
-
line = style_fn(now, level,
|
|
25
|
+
line = style_fn(now, level, t.get(level), t.get(f"label_{level}"), str(message), t, cfg.show_time)
|
|
38
26
|
with cfg._lock:
|
|
39
27
|
print(line)
|
|
40
|
-
|
|
28
|
+
if cfg._file_handle:
|
|
29
|
+
try:
|
|
30
|
+
cfg._file_handle.write(strip_ansi(line) + "\n")
|
|
31
|
+
cfg._file_handle.flush()
|
|
32
|
+
except Exception:
|
|
33
|
+
pass
|
|
41
34
|
except Exception:
|
|
42
35
|
try:
|
|
43
36
|
print(f"[{level.upper()}] {message}")
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
from .colors import Colors
|
|
2
2
|
from .config import get_config
|
|
3
|
-
from .utils import strip_ansi
|
|
3
|
+
from .utils import strip_ansi, get_terminal_width, wrap_lines
|
|
4
4
|
|
|
5
5
|
__all__ = ["divider", "section", "blank", "rule", "banner", "pair"]
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
def _write(message):
|
|
9
|
-
cfg = get_config()
|
|
8
|
+
def _write(cfg, message):
|
|
10
9
|
if cfg._file_handle:
|
|
11
10
|
try:
|
|
12
11
|
cfg._file_handle.write(strip_ansi(message) + "\n")
|
|
@@ -19,11 +18,11 @@ def divider(char="─", length=60, color=None):
|
|
|
19
18
|
try:
|
|
20
19
|
cfg = get_config()
|
|
21
20
|
c = color or cfg.theme.get("divider")
|
|
22
|
-
length = max(1, int(length))
|
|
21
|
+
length = min(max(1, int(length)), get_terminal_width())
|
|
23
22
|
line = f"{c}{str(char)[0] * length}{Colors.RESET}"
|
|
24
23
|
with cfg._lock:
|
|
25
24
|
print(line)
|
|
26
|
-
_write(line)
|
|
25
|
+
_write(cfg, line)
|
|
27
26
|
except Exception:
|
|
28
27
|
print(str(char) * max(1, int(length)))
|
|
29
28
|
|
|
@@ -33,8 +32,9 @@ def section(title="", char="═", length=60):
|
|
|
33
32
|
cfg = get_config()
|
|
34
33
|
t = cfg.theme
|
|
35
34
|
title = str(title)
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
title_len = len(strip_ansi(title))
|
|
36
|
+
length = min(max(title_len + 4, int(length)), get_terminal_width())
|
|
37
|
+
pad = length - title_len - 2
|
|
38
38
|
left = pad // 2
|
|
39
39
|
right = pad - left
|
|
40
40
|
line = (
|
|
@@ -44,14 +44,20 @@ def section(title="", char="═", length=60):
|
|
|
44
44
|
)
|
|
45
45
|
with cfg._lock:
|
|
46
46
|
print(line)
|
|
47
|
-
_write(line)
|
|
47
|
+
_write(cfg, line)
|
|
48
48
|
except Exception:
|
|
49
49
|
print(f"== {title} ==")
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
def blank(count=1):
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
try:
|
|
54
|
+
cfg = get_config()
|
|
55
|
+
with cfg._lock:
|
|
56
|
+
for _ in range(max(1, int(count))):
|
|
57
|
+
print()
|
|
58
|
+
except Exception:
|
|
59
|
+
for _ in range(max(1, int(count))):
|
|
60
|
+
print()
|
|
55
61
|
|
|
56
62
|
|
|
57
63
|
def rule(text="", char="─", length=60):
|
|
@@ -66,16 +72,23 @@ def banner(text="", char="═", padding=2):
|
|
|
66
72
|
cfg = get_config()
|
|
67
73
|
text = str(text)
|
|
68
74
|
padding = max(0, int(padding))
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
term_w = get_terminal_width()
|
|
76
|
+
max_inner = max(term_w - 2, 1)
|
|
77
|
+
lines = wrap_lines(text.split("\n"), max_inner - (padding * 2))
|
|
78
|
+
max_len = max((len(strip_ansi(l)) for l in lines), default=0)
|
|
79
|
+
width = min(max_len + (padding * 2) + 2, term_w)
|
|
72
80
|
t = cfg.theme
|
|
73
81
|
bc, tc, R = t.get("info"), t.get("success"), Colors.RESET
|
|
74
82
|
ch = str(char)[0] if char else "═"
|
|
75
83
|
with cfg._lock:
|
|
76
84
|
print(f"{bc}╔{ch * (width - 2)}╗{R}")
|
|
77
85
|
for l in lines:
|
|
78
|
-
|
|
86
|
+
s_len = len(strip_ansi(l))
|
|
87
|
+
space = max(max_len - s_len, 0)
|
|
88
|
+
lp = space // 2
|
|
89
|
+
rp = space - lp
|
|
90
|
+
padded = f"{' ' * lp}{l}{' ' * rp}"
|
|
91
|
+
print(f"{bc}║{R}{' ' * padding}{tc}{padded}{R}{' ' * padding}{bc}║{R}")
|
|
79
92
|
print(f"{bc}╚{ch * (width - 2)}╝{R}")
|
|
80
93
|
except Exception:
|
|
81
94
|
print(text)
|
|
@@ -89,6 +102,6 @@ def pair(k, v, k_clr=None, v_clr=None):
|
|
|
89
102
|
k, v = str(k), str(v)
|
|
90
103
|
with cfg._lock:
|
|
91
104
|
print(f" {kc}{Colors.BOLD}{k}{Colors.RESET}: {vc}{v}{Colors.RESET}")
|
|
92
|
-
_write(f" {k}: {v}")
|
|
105
|
+
_write(cfg, f" {k}: {v}")
|
|
93
106
|
except Exception:
|
|
94
107
|
print(f" {k}: {v}")
|
|
@@ -4,6 +4,7 @@ import threading
|
|
|
4
4
|
|
|
5
5
|
from .colors import Colors
|
|
6
6
|
from .config import get_config
|
|
7
|
+
from .utils import get_terminal_width
|
|
7
8
|
|
|
8
9
|
__all__ = ["Progress", "Spinner", "Timer"]
|
|
9
10
|
|
|
@@ -28,18 +29,25 @@ class Progress:
|
|
|
28
29
|
|
|
29
30
|
def _render(self):
|
|
30
31
|
try:
|
|
32
|
+
term_w = get_terminal_width()
|
|
31
33
|
pct = self.current / self.total
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
stats = f" ({self.current}/{self.total}) [{time.time() - self._start:.1f}s]"
|
|
35
|
+
label_part = f"{self.color}{self.label}{Colors.RESET} │"
|
|
36
|
+
bar_end = f"│ {Colors.BOLD}{pct * 100:5.1f}%{Colors.RESET}{stats}"
|
|
37
|
+
overhead = len(self.label) + 3 + 10 + len(stats)
|
|
38
|
+
bar_w = min(self.width, max(5, term_w - overhead))
|
|
39
|
+
filled = int(bar_w * pct)
|
|
40
|
+
bar = self.fill * filled + self.empty * (bar_w - filled)
|
|
34
41
|
elapsed = time.time() - self._start
|
|
35
42
|
eta = (elapsed / pct - elapsed) if pct > 0 else 0
|
|
36
|
-
|
|
43
|
+
line = (
|
|
37
44
|
f"\r{self.color}{self.label}{Colors.RESET} "
|
|
38
45
|
f"│{self.color}{bar}{Colors.RESET}│ "
|
|
39
46
|
f"{Colors.BOLD}{pct * 100:5.1f}%{Colors.RESET} "
|
|
40
47
|
f"({self.current}/{self.total}) "
|
|
41
48
|
f"[{elapsed:.1f}s / ETA {eta:.1f}s]"
|
|
42
49
|
)
|
|
50
|
+
sys.stdout.write(line)
|
|
43
51
|
sys.stdout.flush()
|
|
44
52
|
if self.current >= self.total:
|
|
45
53
|
print()
|
|
@@ -64,18 +72,18 @@ class Spinner:
|
|
|
64
72
|
self.color = color or get_config().theme.get("info")
|
|
65
73
|
except Exception:
|
|
66
74
|
self.color = ""
|
|
67
|
-
self.
|
|
75
|
+
self._stop_event = threading.Event()
|
|
68
76
|
self._thread = None
|
|
69
77
|
|
|
70
78
|
def start(self):
|
|
71
|
-
self.
|
|
79
|
+
self._stop_event.clear()
|
|
72
80
|
self._thread = threading.Thread(target=self._spin, daemon=True)
|
|
73
81
|
self._thread.start()
|
|
74
82
|
return self
|
|
75
83
|
|
|
76
84
|
def _spin(self):
|
|
77
85
|
i = 0
|
|
78
|
-
while self.
|
|
86
|
+
while not self._stop_event.is_set():
|
|
79
87
|
try:
|
|
80
88
|
frame = self.frames[i % len(self.frames)]
|
|
81
89
|
sys.stdout.write(f"\r{self.color}{frame}{Colors.RESET} {self.msg}")
|
|
@@ -83,17 +91,17 @@ class Spinner:
|
|
|
83
91
|
except Exception:
|
|
84
92
|
pass
|
|
85
93
|
i += 1
|
|
86
|
-
|
|
94
|
+
self._stop_event.wait(0.08)
|
|
87
95
|
|
|
88
96
|
def stop(self, final=""):
|
|
89
|
-
self.
|
|
97
|
+
self._stop_event.set()
|
|
90
98
|
if self._thread:
|
|
91
99
|
try:
|
|
92
100
|
self._thread.join(timeout=2)
|
|
93
101
|
except Exception:
|
|
94
102
|
pass
|
|
95
103
|
try:
|
|
96
|
-
sys.stdout.write("\r
|
|
104
|
+
sys.stdout.write(f"\r\033[2K\r")
|
|
97
105
|
sys.stdout.flush()
|
|
98
106
|
except Exception:
|
|
99
107
|
pass
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import shutil
|
|
3
|
+
|
|
4
|
+
from .colors import Colors
|
|
5
|
+
|
|
6
|
+
__all__ = ["strip_ansi", "clr", "bold", "italic", "uline"]
|
|
7
|
+
|
|
8
|
+
_ANSI_RE = re.compile(r'\033\[[0-9;]*m')
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def strip_ansi(text):
|
|
12
|
+
try:
|
|
13
|
+
return _ANSI_RE.sub('', str(text))
|
|
14
|
+
except Exception:
|
|
15
|
+
return str(text)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_terminal_width():
|
|
19
|
+
try:
|
|
20
|
+
return shutil.get_terminal_size().columns
|
|
21
|
+
except Exception:
|
|
22
|
+
return 120
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def wrap_line(text, max_width):
|
|
26
|
+
if len(strip_ansi(text)) <= max_width:
|
|
27
|
+
return [text]
|
|
28
|
+
wrapped = []
|
|
29
|
+
current = ""
|
|
30
|
+
current_len = 0
|
|
31
|
+
i = 0
|
|
32
|
+
while i < len(text):
|
|
33
|
+
if text[i] == '\033' and i + 1 < len(text) and text[i + 1] == '[':
|
|
34
|
+
j = i + 2
|
|
35
|
+
while j < len(text) and text[j] not in 'mGHJK':
|
|
36
|
+
j += 1
|
|
37
|
+
if j < len(text):
|
|
38
|
+
j += 1
|
|
39
|
+
current += text[i:j]
|
|
40
|
+
i = j
|
|
41
|
+
else:
|
|
42
|
+
if current_len >= max_width:
|
|
43
|
+
wrapped.append(current)
|
|
44
|
+
current = ""
|
|
45
|
+
current_len = 0
|
|
46
|
+
current += text[i]
|
|
47
|
+
current_len += 1
|
|
48
|
+
i += 1
|
|
49
|
+
if current:
|
|
50
|
+
wrapped.append(current)
|
|
51
|
+
return wrapped if wrapped else [text]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def wrap_lines(lines, max_width):
|
|
55
|
+
result = []
|
|
56
|
+
for line in lines:
|
|
57
|
+
result.extend(wrap_line(line, max_width))
|
|
58
|
+
return result
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def clr(text, color):
|
|
62
|
+
return f"{color}{text}{Colors.RESET}"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def bold(text):
|
|
66
|
+
return f"{Colors.BOLD}{text}{Colors.RESET}"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def italic(text):
|
|
70
|
+
return f"{Colors.ITALIC}{text}{Colors.RESET}"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def uline(text):
|
|
74
|
+
return f"{Colors.UNDERLINE}{text}{Colors.RESET}"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from .colors import Colors
|
|
2
2
|
from .config import get_config
|
|
3
|
-
from .utils import strip_ansi
|
|
3
|
+
from .utils import strip_ansi, get_terminal_width, wrap_lines
|
|
4
4
|
|
|
5
5
|
__all__ = ["panel", "table", "box"]
|
|
6
6
|
|
|
@@ -34,12 +34,18 @@ def panel(content="", title="", width=50, color=None, style="rounded"):
|
|
|
34
34
|
R = Colors.RESET
|
|
35
35
|
tl, tr, bl, br, h, v = _PANEL_CHARS.get(style, _PANEL_CHARS["rounded"])
|
|
36
36
|
content = str(content)
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
term_w = get_terminal_width()
|
|
38
|
+
max_inner = max(term_w - 4, 8)
|
|
39
|
+
lines = wrap_lines(content.split("\n"), max_inner)
|
|
40
|
+
max_line_len = max((len(strip_ansi(l)) for l in lines), default=0)
|
|
41
|
+
width = max(width, max_line_len + 4, 8)
|
|
42
|
+
if title:
|
|
43
|
+
title = str(title)
|
|
44
|
+
width = max(width, len(strip_ansi(title)) + 6)
|
|
45
|
+
width = min(width, term_w)
|
|
39
46
|
inner_w = width - 4
|
|
40
47
|
with cfg._lock:
|
|
41
48
|
if title:
|
|
42
|
-
title = str(title)
|
|
43
49
|
header_pad = max(width - len(strip_ansi(title)) - 5, 1)
|
|
44
50
|
print(f"{bc}{tl}{h} {Colors.BOLD}{title}{R}{bc} {h * header_pad}{tr}{R}")
|
|
45
51
|
else:
|
|
@@ -64,13 +70,14 @@ def table(headers=None, rows=None, color=None, style="rounded"):
|
|
|
64
70
|
hc = cfg.theme.get("success")
|
|
65
71
|
R, B = Colors.RESET, Colors.BOLD
|
|
66
72
|
tl, tr, bl, br, h, v, tm, bm, ml, mr, mm = _TABLE_CHARS.get(style, _TABLE_CHARS["rounded"])
|
|
67
|
-
col_w = [len(hdr) for hdr in headers]
|
|
73
|
+
col_w = [len(strip_ansi(hdr)) for hdr in headers]
|
|
68
74
|
for r in rows:
|
|
69
75
|
for i, c in enumerate(r):
|
|
76
|
+
vl = len(strip_ansi(c))
|
|
70
77
|
if i < len(col_w):
|
|
71
|
-
col_w[i] = max(col_w[i],
|
|
78
|
+
col_w[i] = max(col_w[i], vl)
|
|
72
79
|
else:
|
|
73
|
-
col_w.append(
|
|
80
|
+
col_w.append(vl)
|
|
74
81
|
|
|
75
82
|
def _sep(left, mid, right, fill):
|
|
76
83
|
return f"{bc}{left}{mid.join(fill * (w + 2) for w in col_w)}{right}{R}"
|
|
@@ -78,8 +85,9 @@ def table(headers=None, rows=None, color=None, style="rounded"):
|
|
|
78
85
|
def _row(cells, c=""):
|
|
79
86
|
padded = []
|
|
80
87
|
for i, cell in enumerate(cells):
|
|
81
|
-
w = col_w[i] if i < len(col_w) else len(cell)
|
|
82
|
-
|
|
88
|
+
w = col_w[i] if i < len(col_w) else len(strip_ansi(cell))
|
|
89
|
+
pad = max(w - len(strip_ansi(cell)), 0)
|
|
90
|
+
padded.append(f" {c}{cell}{' ' * pad}{R} ")
|
|
83
91
|
return f"{bc}{v}{R}" + f"{bc}{v}{R}".join(padded) + f"{bc}{v}{R}"
|
|
84
92
|
|
|
85
93
|
with cfg._lock:
|
|
@@ -105,10 +113,13 @@ def box(text="", width=None, style="rounded", color=None, text_clr=None, align="
|
|
|
105
113
|
tl, tr, bl, br, h, v = _BOX_CHARS.get(style, _BOX_CHARS["rounded"])
|
|
106
114
|
text = str(text)
|
|
107
115
|
padding = max(0, int(padding))
|
|
108
|
-
|
|
116
|
+
term_w = get_terminal_width()
|
|
117
|
+
max_inner = max(term_w - 4, 1)
|
|
118
|
+
lines = wrap_lines(text.split("\n"), max_inner)
|
|
109
119
|
max_line = max((len(strip_ansi(l)) for l in lines), default=0)
|
|
110
120
|
inner_w = (width - 4) if width else max_line + (padding * 2)
|
|
111
|
-
inner_w = max(inner_w, 1)
|
|
121
|
+
inner_w = max(inner_w, max_line, 1)
|
|
122
|
+
inner_w = min(inner_w, max_inner)
|
|
112
123
|
total_w = inner_w + 4
|
|
113
124
|
with cfg._lock:
|
|
114
125
|
print(f"{bc}{tl}{h * (total_w - 2)}{tr}{R}")
|
|
@@ -116,9 +127,9 @@ def box(text="", width=None, style="rounded", color=None, text_clr=None, align="
|
|
|
116
127
|
s_len = len(strip_ansi(l))
|
|
117
128
|
space = max(inner_w - s_len, 0)
|
|
118
129
|
if align == "center":
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
padded = f"{' ' *
|
|
130
|
+
lp = space // 2
|
|
131
|
+
rp = space - lp
|
|
132
|
+
padded = f"{' ' * lp}{tc}{l}{R}{' ' * rp}"
|
|
122
133
|
elif align == "right":
|
|
123
134
|
padded = f"{' ' * space}{tc}{l}{R}"
|
|
124
135
|
else:
|
|
@@ -127,4 +138,3 @@ def box(text="", width=None, style="rounded", color=None, text_clr=None, align="
|
|
|
127
138
|
print(f"{bc}{bl}{h * (total_w - 2)}{br}{R}")
|
|
128
139
|
except Exception:
|
|
129
140
|
print(text)
|
|
130
|
-
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "hexlogger"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.3"
|
|
8
8
|
description = "Premium console logging library with themes, gradients, panels, tables, progress bars, and spinners."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
|
|
3
|
-
from .colors import Colors
|
|
4
|
-
|
|
5
|
-
__all__ = ["strip_ansi", "clr", "bold", "italic", "uline"]
|
|
6
|
-
|
|
7
|
-
_ANSI_RE = re.compile(r'\033\[[0-9;]*m')
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def strip_ansi(text):
|
|
11
|
-
try:
|
|
12
|
-
return _ANSI_RE.sub('', str(text))
|
|
13
|
-
except Exception:
|
|
14
|
-
return str(text)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def clr(text, color):
|
|
18
|
-
return f"{color}{text}{Colors.RESET}"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def bold(text):
|
|
22
|
-
return f"{Colors.BOLD}{text}{Colors.RESET}"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def italic(text):
|
|
26
|
-
return f"{Colors.ITALIC}{text}{Colors.RESET}"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def uline(text):
|
|
30
|
-
return f"{Colors.UNDERLINE}{text}{Colors.RESET}"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|