Skip to content

Commit 5c5c3e1

Browse files
hugovkambv
authored andcommitted
Add theming to unittest
1 parent ca34939 commit 5c5c3e1

File tree

2 files changed

+51
-48
lines changed

2 files changed

+51
-48
lines changed

Lib/_colorize.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,20 @@ class Traceback(ThemeSection):
134134
reset: str = ANSIColors.RESET
135135

136136

137+
@dataclass(frozen=True)
138+
class Unittest(ThemeSection):
139+
passed: str = ANSIColors.GREEN
140+
warn: str = ANSIColors.YELLOW
141+
fail: str = ANSIColors.RED
142+
fail_info: str = ANSIColors.BOLD_RED
143+
reset: str = ANSIColors.RESET
144+
145+
137146
@dataclass(frozen=True)
138147
class Theme:
139148
repl: REPL = field(default_factory=REPL)
140149
traceback: Traceback = field(default_factory=Traceback)
150+
unittest: Unittest = field(default_factory=Unittest)
141151

142152
def copy_with(
143153
self,

Lib/unittest/runner.py

Lines changed: 41 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import time
55
import warnings
66

7-
from _colorize import get_colors
7+
from _colorize import get_theme
88

99
from . import result
1010
from .case import _SubTest
@@ -45,7 +45,7 @@ def __init__(self, stream, descriptions, verbosity, *, durations=None):
4545
self.showAll = verbosity > 1
4646
self.dots = verbosity == 1
4747
self.descriptions = descriptions
48-
self._ansi = get_colors(file=stream)
48+
self._theme = get_theme(tty_file=stream).unittest
4949
self._newline = True
5050
self.durations = durations
5151

@@ -79,101 +79,99 @@ def _write_status(self, test, status):
7979

8080
def addSubTest(self, test, subtest, err):
8181
if err is not None:
82-
red, reset = self._ansi.RED, self._ansi.RESET
82+
t = self._theme
8383
if self.showAll:
8484
if issubclass(err[0], subtest.failureException):
85-
self._write_status(subtest, f"{red}FAIL{reset}")
85+
self._write_status(subtest, f"{t.fail}FAIL{t.reset}")
8686
else:
87-
self._write_status(subtest, f"{red}ERROR{reset}")
87+
self._write_status(subtest, f"{t.fail}ERROR{t.reset}")
8888
elif self.dots:
8989
if issubclass(err[0], subtest.failureException):
90-
self.stream.write(f"{red}F{reset}")
90+
self.stream.write(f"{t.fail}F{t.reset}")
9191
else:
92-
self.stream.write(f"{red}E{reset}")
92+
self.stream.write(f"{t.fail}E{t.reset}")
9393
self.stream.flush()
9494
super(TextTestResult, self).addSubTest(test, subtest, err)
9595

9696
def addSuccess(self, test):
9797
super(TextTestResult, self).addSuccess(test)
98-
green, reset = self._ansi.GREEN, self._ansi.RESET
98+
t = self._theme
9999
if self.showAll:
100-
self._write_status(test, f"{green}ok{reset}")
100+
self._write_status(test, f"{t.passed}ok{t.reset}")
101101
elif self.dots:
102-
self.stream.write(f"{green}.{reset}")
102+
self.stream.write(f"{t.passed}.{t.reset}")
103103
self.stream.flush()
104104

105105
def addError(self, test, err):
106106
super(TextTestResult, self).addError(test, err)
107-
red, reset = self._ansi.RED, self._ansi.RESET
107+
t = self._theme
108108
if self.showAll:
109-
self._write_status(test, f"{red}ERROR{reset}")
109+
self._write_status(test, f"{t.fail}ERROR{t.reset}")
110110
elif self.dots:
111-
self.stream.write(f"{red}E{reset}")
111+
self.stream.write(f"{t.fail}E{t.reset}")
112112
self.stream.flush()
113113

114114
def addFailure(self, test, err):
115115
super(TextTestResult, self).addFailure(test, err)
116-
red, reset = self._ansi.RED, self._ansi.RESET
116+
t = self._theme
117117
if self.showAll:
118-
self._write_status(test, f"{red}FAIL{reset}")
118+
self._write_status(test, f"{t.fail}FAIL{t.reset}")
119119
elif self.dots:
120-
self.stream.write(f"{red}F{reset}")
120+
self.stream.write(f"{t.fail}F{t.reset}")
121121
self.stream.flush()
122122

123123
def addSkip(self, test, reason):
124124
super(TextTestResult, self).addSkip(test, reason)
125-
yellow, reset = self._ansi.YELLOW, self._ansi.RESET
125+
t = self._theme
126126
if self.showAll:
127-
self._write_status(test, f"{yellow}skipped{reset} {reason!r}")
127+
self._write_status(test, f"{t.warn}skipped{t.reset} {reason!r}")
128128
elif self.dots:
129-
self.stream.write(f"{yellow}s{reset}")
129+
self.stream.write(f"{t.warn}s{t.reset}")
130130
self.stream.flush()
131131

132132
def addExpectedFailure(self, test, err):
133133
super(TextTestResult, self).addExpectedFailure(test, err)
134-
yellow, reset = self._ansi.YELLOW, self._ansi.RESET
134+
t = self._theme
135135
if self.showAll:
136-
self.stream.writeln(f"{yellow}expected failure{reset}")
136+
self.stream.writeln(f"{t.warn}expected failure{t.reset}")
137137
self.stream.flush()
138138
elif self.dots:
139-
self.stream.write(f"{yellow}x{reset}")
139+
self.stream.write(f"{t.warn}x{t.reset}")
140140
self.stream.flush()
141141

142142
def addUnexpectedSuccess(self, test):
143143
super(TextTestResult, self).addUnexpectedSuccess(test)
144-
red, reset = self._ansi.RED, self._ansi.RESET
144+
t = self._theme
145145
if self.showAll:
146-
self.stream.writeln(f"{red}unexpected success{reset}")
146+
self.stream.writeln(f"{t.fail}unexpected success{t.reset}")
147147
self.stream.flush()
148148
elif self.dots:
149-
self.stream.write(f"{red}u{reset}")
149+
self.stream.write(f"{t.fail}u{t.reset}")
150150
self.stream.flush()
151151

152152
def printErrors(self):
153-
bold_red = self._ansi.BOLD_RED
154-
red = self._ansi.RED
155-
reset = self._ansi.RESET
153+
t = self._theme
156154
if self.dots or self.showAll:
157155
self.stream.writeln()
158156
self.stream.flush()
159-
self.printErrorList(f"{red}ERROR{reset}", self.errors)
160-
self.printErrorList(f"{red}FAIL{reset}", self.failures)
157+
self.printErrorList(f"{t.fail}ERROR{t.reset}", self.errors)
158+
self.printErrorList(f"{t.fail}FAIL{t.reset}", self.failures)
161159
unexpectedSuccesses = getattr(self, "unexpectedSuccesses", ())
162160
if unexpectedSuccesses:
163161
self.stream.writeln(self.separator1)
164162
for test in unexpectedSuccesses:
165163
self.stream.writeln(
166-
f"{red}UNEXPECTED SUCCESS{bold_red}: "
167-
f"{self.getDescription(test)}{reset}"
164+
f"{t.fail}UNEXPECTED SUCCESS{t.fail_info}: "
165+
f"{self.getDescription(test)}{t.reset}"
168166
)
169167
self.stream.flush()
170168

171169
def printErrorList(self, flavour, errors):
172-
bold_red, reset = self._ansi.BOLD_RED, self._ansi.RESET
170+
t = self._theme
173171
for test, err in errors:
174172
self.stream.writeln(self.separator1)
175173
self.stream.writeln(
176-
f"{flavour}{bold_red}: {self.getDescription(test)}{reset}"
174+
f"{flavour}{t.fail_info}: {self.getDescription(test)}{t.reset}"
177175
)
178176
self.stream.writeln(self.separator2)
179177
self.stream.writeln("%s" % err)
@@ -286,31 +284,26 @@ def run(self, test):
286284
expected_fails, unexpected_successes, skipped = results
287285

288286
infos = []
289-
ansi = get_colors(file=self.stream)
290-
bold_red = ansi.BOLD_RED
291-
green = ansi.GREEN
292-
red = ansi.RED
293-
reset = ansi.RESET
294-
yellow = ansi.YELLOW
287+
t = get_theme(tty_file=self.stream).unittest
295288

296289
if not result.wasSuccessful():
297-
self.stream.write(f"{bold_red}FAILED{reset}")
290+
self.stream.write(f"{t.fail_info}FAILED{t.reset}")
298291
failed, errored = len(result.failures), len(result.errors)
299292
if failed:
300-
infos.append(f"{bold_red}failures={failed}{reset}")
293+
infos.append(f"{t.fail_info}failures={failed}{t.reset}")
301294
if errored:
302-
infos.append(f"{bold_red}errors={errored}{reset}")
295+
infos.append(f"{t.fail_info}errors={errored}{t.reset}")
303296
elif run == 0 and not skipped:
304-
self.stream.write(f"{yellow}NO TESTS RAN{reset}")
297+
self.stream.write(f"{t.warn}NO TESTS RAN{t.reset}")
305298
else:
306-
self.stream.write(f"{green}OK{reset}")
299+
self.stream.write(f"{t.passed}OK{t.reset}")
307300
if skipped:
308-
infos.append(f"{yellow}skipped={skipped}{reset}")
301+
infos.append(f"{t.warn}skipped={skipped}{t.reset}")
309302
if expected_fails:
310-
infos.append(f"{yellow}expected failures={expected_fails}{reset}")
303+
infos.append(f"{t.warn}expected failures={expected_fails}{t.reset}")
311304
if unexpected_successes:
312305
infos.append(
313-
f"{red}unexpected successes={unexpected_successes}{reset}"
306+
f"{t.fail}unexpected successes={unexpected_successes}{t.reset}"
314307
)
315308
if infos:
316309
self.stream.writeln(" (%s)" % (", ".join(infos),))

0 commit comments

Comments
 (0)