def overwrite(self, line): if not isinstance(line, str): raise TypeError("line must be str, not {}" .format(type(line).__name__)) # Do nothing if the line has not changed. if self._prev_line is not None and self._prev_line == line: return written_line = line if self.has_overwrite: self.write(self._cr) termwidth = self._get_termwidth() if termwidth: truncinfo = ansi_string_truncinfo(line, termwidth) trunc_pos, line_visual_len, line_has_ansi = truncinfo written_line = line[:trunc_pos] self.write(written_line) if not self.has_overwrite: self.write("\n") if self.has_overwrite and self._prev_line is not None: if self._termnfo.clear_eol: self.write(self._termnfo.clear_eol) else: truncinfo = ansi_string_truncinfo(self._prev_line, termwidth) _, prev_line_visual_len, _ = truncinfo if line_visual_len < prev_line_visual_len: eraser = "" if line_has_ansi: eraser += self._termnfo.reset_all eraser += " " * (prev_line_visual_len - line_visual_len) self.write(eraser) self._prev_line = line self._output.flush()
def test_empty_string(self): self.assertEqual((0, 0, False), ansi_string_truncinfo("", 0)) self.assertEqual((0, 0, False), ansi_string_truncinfo("", 1)) self.assertEqual((0, 0, False), ansi_string_truncinfo("", 100)) self.assertEqual("", truncate_ansi_string("", 0)) self.assertEqual("", truncate_ansi_string("", 1)) self.assertEqual("", truncate_ansi_string("", 100))
def test_size_3_ansi_first(self): fixture = self.termnfo.fore_red + "text" size = 3 expected = self.termnfo.fore_red + "tex" actual = truncate_ansi_string(fixture, size) self.assertEqual(expected, actual) self.assertEqual((len(expected), size, True), ansi_string_truncinfo(fixture, size))
def test_size_0_ansi_first(self): fixture = self.termnfo.fore_red + "text" size = 0 expected = "" actual = truncate_ansi_string(fixture, size) self.assertEqual(expected, actual) self.assertEqual((0, 0, False), ansi_string_truncinfo(fixture, size))
def test_size_exceed_ansi_first_middle_last(self): fixture = self.termnfo.fore_blue + "123" + self.termnfo.fore_red + "456" + self.termnfo.fore_green size = 1000 expected = self.termnfo.fore_blue + "123" + self.termnfo.fore_red + "456" + self.termnfo.fore_green actual = truncate_ansi_string(fixture, size) self.assertEqual(expected, actual) self.assertEqual((len(expected), 6, True), ansi_string_truncinfo(fixture, size))
def test_size_0_ansi_first_middle_last(self): fixture = self.termnfo.fore_blue + "123" + self.termnfo.fore_red + "red" + self.termnfo.fore_green size = 0 expected = "" actual = truncate_ansi_string(fixture, size) self.assertEqual(expected, actual) self.assertEqual((len(expected), size, False), ansi_string_truncinfo(fixture, size))
def test_size_6_ansi_first_middle(self): fixture = self.termnfo.fore_blue + "123" + self.termnfo.fore_red + "456" size = 6 expected = self.termnfo.fore_blue + "123" + self.termnfo.fore_red + "456" actual = truncate_ansi_string(fixture, size) self.assertEqual(expected, actual) self.assertEqual((len(expected), size, True), ansi_string_truncinfo(fixture, size))
def test_size_exceed_ansi_middle(self): fixture = "123" + self.termnfo.fore_red + "456" size = 10000 expected = "123" + self.termnfo.fore_red + "456" actual = truncate_ansi_string(fixture, size) self.assertEqual(expected, actual) self.assertEqual((len(expected), 6, True), ansi_string_truncinfo(fixture, size))
def test_size_3_ansi_middle(self): fixture = "123" + self.termnfo.fore_red + "red" size = 3 expected = "123" actual = truncate_ansi_string(fixture, size) self.assertEqual(expected, actual) self.assertEqual((len(expected), size, False), ansi_string_truncinfo(fixture, size))
def overwrite_message(self, *args, ellipse_index=None, ellipse="..."): for i, arg in enumerate(args): if not isinstance(arg, str): raise TypeError("positional argument {} must be a str, not {}" .format(i, type(arg).__name__)) if ellipse_index is None or not self.has_overwrite: return self.overwrite("".join(args)) termwidth = self._get_termwidth() if not termwidth: return self.overwrite("".join(args)) prefix = "".join(args[:ellipse_index]) p_trunc, p_vlen, _ = ansi_string_truncinfo(prefix, termwidth) if p_trunc < len(prefix): return self.overwrite("".join(args)) suffix = "".join(args[ellipse_index+1:]) s_trunc, s_vlen, _ = ansi_string_truncinfo(suffix, termwidth-p_vlen) msg = args[ellipse_index] m_trunc, m_vlen, m_ansi = ansi_string_truncinfo(msg, termwidth-p_vlen-s_vlen) assert m_ansi is False, "we do not support ellipse in the middle with ansi char at the moment" if m_trunc < len(msg): p = (m_vlen - len(ellipse)) // 2 msg = msg[:p] + ellipse + msg[-p:] return self.overwrite(prefix + msg[:m_trunc] + suffix)
def test_size_exceed_no_ansi(self): text = "foobarblue" s = 10000 self.assertEqual(text, truncate_ansi_string(text, s)) self.assertEqual((len(text), len(text), False), ansi_string_truncinfo(text, s))
def test_size_3_no_ansi(self): q = "foobarblue" a = "foo" s = 3 self.assertEqual(a, truncate_ansi_string(q, s)) self.assertEqual((s, s, False), ansi_string_truncinfo(q, s))
def test_use_case(self): fixture = ( "[ 50%|253.71|" + self.termnfo.fore_green + "2" + self.termnfo.reset_all + "|" + self.termnfo.fore_red + "0" + self.termnfo.reset_all + "|" + self.termnfo.fore_magenta + "0" + self.termnfo.reset_all + "|" + self.termnfo.fore_blue + "0" + self.termnfo.reset_all + "|" + self.termnfo.fore_yellow + "0" + self.termnfo.reset_all + "|" + self.termnfo.fore_cyan + "0" + self.termnfo.reset_all + "]" + self.termnfo.fore_green + " SUCCESS " + self.termnfo.reset_all + ": testtest.test_allgood.Case1.test_success2 (0:00:00.252080)" ) size = 50 expected = ( "[ 50%|253.71|" + self.termnfo.fore_green + "2" + self.termnfo.reset_all + "|" + self.termnfo.fore_red + "0" + self.termnfo.reset_all + "|" + self.termnfo.fore_magenta + "0" + self.termnfo.reset_all + "|" + self.termnfo.fore_blue + "0" + self.termnfo.reset_all + "|" + self.termnfo.fore_yellow + "0" + self.termnfo.reset_all + "|" + self.termnfo.fore_cyan + "0" + self.termnfo.reset_all + "]" + self.termnfo.fore_green + " SUCCESS " + self.termnfo.reset_all + ": testtest.test_" ) actual = truncate_ansi_string(fixture, size) self.assertEqual(expected, actual) self.assertEqual((len(expected), size, True), ansi_string_truncinfo(fixture, size))
def test_none_string(self): with self.assertRaises(ValueError): ansi_string_truncinfo(None, 1) with self.assertRaises(ValueError): truncate_ansi_string(None, 1)
def test_negative(self): with self.assertRaises(ValueError): ansi_string_truncinfo("", -1) with self.assertRaises(ValueError): truncate_ansi_string("", -1)