diff options
-rw-r--r-- | urwid/canvas.py | 33 | ||||
-rwxr-xr-x | urwid/curses_display.py | 8 | ||||
-rw-r--r-- | urwid/tests/test_canvas.py | 6 | ||||
-rw-r--r-- | urwid/tests/test_font.py | 30 | ||||
-rw-r--r-- | urwid/tests/test_graphics.py | 17 | ||||
-rw-r--r-- | urwid/tests/test_text_layout.py | 63 | ||||
-rw-r--r-- | urwid/tests/test_util.py | 22 | ||||
-rw-r--r-- | urwid/tests/test_widget.py | 33 |
8 files changed, 172 insertions, 40 deletions
diff --git a/urwid/canvas.py b/urwid/canvas.py index ed71c54..4d467e8 100644 --- a/urwid/canvas.py +++ b/urwid/canvas.py @@ -61,7 +61,7 @@ class CanvasCache: """ _widgets = {} _refs = {} - _deps = {} + _deps: dict[Widget, list[Widget]] = {} hits = 0 fetches = 0 cleanups = 0 @@ -157,7 +157,7 @@ class CanvasCache: @classmethod def cleanup(cls, ref): - cls.cleanups += 1 # collect stats + cls.cleanups += 1 # collect stats w = cls._refs.get(ref, None) del cls._refs[ref] @@ -198,12 +198,16 @@ class Canvas: """ cacheable = True - _finalized_error = CanvasError("This canvas has been finalized. " + _finalized_error = CanvasError( + "This canvas has been finalized. " "Use CompositeCanvas to wrap this canvas if " - "you need to make changes.") - _renamed_error = CanvasError("The old Canvas class is now called " + "you need to make changes." + ) + _renamed_error = CanvasError( + "The old Canvas class is now called " "TextCanvas. Canvas is now the base class for all canvas " - "classes.") + "classes." + ) def __init__( self, @@ -221,7 +225,12 @@ class Canvas: self.coords = {} self.shortcuts = {} - def finalize(self, widget, size, focus): + def finalize( + self, + widget: Widget, + size: tuple[()] | tuple[int] | tuple[int, int], + focus: bool, + ) -> None: """ Mark this canvas as finalized (should not be any future changes to its content). This is required before caching @@ -386,9 +395,9 @@ class TextCanvas(Canvas): maxcol = 0 if attr is None: - attr = [[]] * len(text) + attr = [[] for _ in range(len(text))] if cs is None: - cs = [[]] * len(text) + cs = [[] for _ in range(len(text))] # pad text and attr to maxcol for i in range(len(text)): @@ -397,11 +406,11 @@ class TextCanvas(Canvas): raise CanvasError(f"Canvas text is wider than the maxcol specified \n{maxcol!r}\n{widths!r}\n{text!r}") if w < maxcol: text[i] += b''.rjust(maxcol - w) - a_gap = len(text[i]) - rle_len( attr[i] ) + a_gap = len(text[i]) - rle_len(attr[i]) if a_gap < 0: - raise CanvasError(f"Attribute extends beyond text \n{text[i]!r}\n{attr[i]!r}" ) + raise CanvasError(f"Attribute extends beyond text \n{text[i]!r}\n{attr[i]!r}") if a_gap: - rle_append_modify( attr[i], (None, a_gap)) + rle_append_modify(attr[i], (None, a_gap)) cs_gap = len(text[i]) - rle_len( cs[i] ) if cs_gap < 0: diff --git a/urwid/curses_display.py b/urwid/curses_display.py index e9519f7..86805f8 100755 --- a/urwid/curses_display.py +++ b/urwid/curses_display.py @@ -597,10 +597,10 @@ class _test: attr += [[],[],[]] cols,rows = self.ui.get_cols_rows() keys = None - while keys!=['q']: - r.text=([t.ljust(cols) for t in text]+[""]*rows)[:rows] - r.attr=(attr+[[]]*rows) [:rows] - self.ui.draw_screen((cols,rows),r) + while keys != ['q']: + r.text = ([t.ljust(cols) for t in text] + [""] * rows)[:rows] + r.attr = (attr + [[] for _ in range(rows)])[:rows] + self.ui.draw_screen((cols, rows), r) keys, raw = self.ui.get_input( raw_keys = True ) if 'window resize' in keys: cols, rows = self.ui.get_cols_rows() diff --git a/urwid/tests/test_canvas.py b/urwid/tests/test_canvas.py index 5a1d454..d0c624c 100644 --- a/urwid/tests/test_canvas.py +++ b/urwid/tests/test_canvas.py @@ -302,6 +302,12 @@ class CanvasJoinTest(unittest.TestCase): class CanvasOverlayTest(unittest.TestCase): + def setUp(self) -> None: + self.old_encoding = urwid.util._target_encoding + + def tearDown(self) -> None: + urwid.set_encoding(self.old_encoding) + def cotest(self, desc, bgt, bga, fgt, fga, l, r, et): bgt = bgt.encode('iso8859-1') fgt = fgt.encode('iso8859-1') diff --git a/urwid/tests/test_font.py b/urwid/tests/test_font.py new file mode 100644 index 0000000..3c9be7a --- /dev/null +++ b/urwid/tests/test_font.py @@ -0,0 +1,30 @@ +from __future__ import annotations + +import unittest + +import urwid + + +class TestFontRender(unittest.TestCase): + def setUp(self) -> None: + self.old_encoding = urwid.util._target_encoding + urwid.set_encoding("utf-8") + + def tearDown(self) -> None: + urwid.set_encoding(self.old_encoding) + + def test_001_basic(self): + font = urwid.Thin3x3Font() + rendered = b'\n'.join(font.render("1").text).decode() + expected = ' ┐ \n │ \n ┴ ' + self.assertEqual(expected, rendered) + + def test_002_non_rect(self): + """Test non rect symbol, which causes spaces based padding. + + Lines as bytes should be not equal length. + """ + font = urwid.Thin3x3Font() + rendered = b'\n'.join(font.render("2").text).decode() + expected = '┌─┐\n┌─┘\n└─ ' + self.assertEqual(expected, rendered) diff --git a/urwid/tests/test_graphics.py b/urwid/tests/test_graphics.py index f731208..1ae1f98 100644 --- a/urwid/tests/test_graphics.py +++ b/urwid/tests/test_graphics.py @@ -7,6 +7,13 @@ from urwid import graphics class LineBoxTest(unittest.TestCase): + def setUp(self) -> None: + self.old_encoding = urwid.util._target_encoding + urwid.set_encoding("utf-8") + + def tearDown(self) -> None: + urwid.set_encoding(self.old_encoding) + def border(self, tl, t, tr, l, r, bl, b, br): return [b''.join([tl, t, tr]), b''.join([l, b" ", r]), @@ -14,7 +21,6 @@ class LineBoxTest(unittest.TestCase): def test_linebox_pack(self): # Bug #346 'pack' Padding does not run with LineBox - urwid.set_encoding("utf-8") t = urwid.Text("AAA\nCCC\nDDD") size = t.pack() l = urwid.LineBox(t) @@ -23,7 +29,6 @@ class LineBoxTest(unittest.TestCase): self.assertEqual(l.pack()[1], size[1] + 2) def test_linebox_border(self): - urwid.set_encoding("utf-8") t = urwid.Text("") l = urwid.LineBox(t).render((3,)).text @@ -87,8 +92,14 @@ class BarGraphTest(unittest.TestCase): (1,[(3,3)]) ] ) class SmoothBarGraphTest(unittest.TestCase): + def setUp(self) -> None: + self.old_encoding = urwid.util._target_encoding + urwid.set_encoding("utf-8") + + def tearDown(self) -> None: + urwid.set_encoding(self.old_encoding) + def sbgtest(self, desc, data, top, exp ): - urwid.set_encoding('utf-8') g = urwid.BarGraph( ['black','red','blue'], None, {(1,0):'red/black', (2,1):'blue/red'}) g.set_data( data, top ) diff --git a/urwid/tests/test_text_layout.py b/urwid/tests/test_text_layout.py index c87d12c..95cba1c 100644 --- a/urwid/tests/test_text_layout.py +++ b/urwid/tests/test_text_layout.py @@ -1,11 +1,24 @@ from __future__ import annotations +import contextlib import unittest +from collections.abc import Generator import urwid from urwid import text_layout +@contextlib.contextmanager +def encoding(encoding_name: str) -> Generator[None, None, None]: + old_encoding = 'ascii' # Default fallback value + try: + old_encoding = urwid.util._target_encoding + urwid.set_encoding(encoding_name) + yield + finally: + urwid.set_encoding(old_encoding) + + class CalcBreaksTest: def cbtest(self, width, exp): result = text_layout.default_layout.calculate_text_segments( @@ -33,8 +46,12 @@ class CalcBreaksCharTest(CalcBreaksTest, unittest.TestCase): class CalcBreaksDBCharTest(CalcBreaksTest, unittest.TestCase): def setUp(self): + self.old_encoding = urwid.util._target_encoding urwid.set_encoding("euc-jp") + def tearDown(self) -> None: + urwid.set_encoding(self.old_encoding) + mode = 'any' text = "abfgh\xA1\xA1j\xA1\xA1xskhtrvs\naltjhgsdf\xA1\xA1jahtshgf" # tests @@ -68,8 +85,12 @@ class CalcBreaksWordTest2(CalcBreaksTest, unittest.TestCase): class CalcBreaksDBWordTest(CalcBreaksTest, unittest.TestCase): def setUp(self): + self.old_encoding = urwid.util._target_encoding urwid.set_encoding("euc-jp") + def tearDown(self) -> None: + urwid.set_encoding(self.old_encoding) + mode = 'space' text = "hel\xA1\xA1 world\nout-\xA1\xA1tre blah" # tests @@ -81,9 +102,13 @@ class CalcBreaksDBWordTest(CalcBreaksTest, unittest.TestCase): class CalcBreaksUTF8Test(CalcBreaksTest, unittest.TestCase): - def setUp(self): + def setUp(self) -> None: + self.old_encoding = urwid.util._target_encoding urwid.set_encoding("utf-8") + def tearDown(self) -> None: + urwid.set_encoding(self.old_encoding) + mode = 'space' text = '\xe6\x9b\xbf\xe6\xb4\xbc\xe6\xb8\x8e\xe6\xba\x8f\xe6\xbd\xba' do = [ @@ -95,20 +120,28 @@ class CalcBreaksUTF8Test(CalcBreaksTest, unittest.TestCase): class CalcBreaksCantDisplayTest(unittest.TestCase): def test(self): - urwid.set_encoding("euc-jp") - self.assertRaises(text_layout.CanNotDisplayText, - text_layout.default_layout.calculate_text_segments, - b'\xA1\xA1', 1, 'space' ) - urwid.set_encoding("utf-8") - self.assertRaises(text_layout.CanNotDisplayText, - text_layout.default_layout.calculate_text_segments, - b'\xe9\xa2\x96', 1, 'space' ) + with encoding("euc-jp"): + self.assertRaises( + text_layout.CanNotDisplayText, + text_layout.default_layout.calculate_text_segments, + b'\xA1\xA1', 1, 'space' + ) + with encoding("utf-8"): + self.assertRaises( + text_layout.CanNotDisplayText, + text_layout.default_layout.calculate_text_segments, + b'\xe9\xa2\x96', 1, 'space' + ) class SubsegTest(unittest.TestCase): def setUp(self): + self.old_encoding = urwid.util._target_encoding urwid.set_encoding("euc-jp") + def tearDown(self) -> None: + urwid.set_encoding(self.old_encoding) + def st(self, seg, text, start, end, exp): text = text.encode('iso8859-1') s = urwid.LayoutSegment(seg) @@ -151,9 +184,13 @@ class SubsegTest(unittest.TestCase): class CalcTranslateTest: - def setUp(self): + def setUp(self) -> None: + self.old_encoding = urwid.util._target_encoding urwid.set_encoding("utf-8") + def tearDown(self) -> None: + urwid.set_encoding(self.old_encoding) + def test1_left(self): result = urwid.default_layout.layout( self.text, self.width, 'left', self.mode) @@ -225,9 +262,13 @@ class CalcTranslateWordTest2(CalcTranslateTest, unittest.TestCase): class CalcTranslateWordTest3(CalcTranslateTest, unittest.TestCase): - def setUp(self): + def setUp(self) -> None: + self.old_encoding = urwid.util._target_encoding urwid.set_encoding('utf-8') + def tearDown(self) -> None: + urwid.set_encoding(self.old_encoding) + text = b'\xe6\x9b\xbf\xe6\xb4\xbc\n\xe6\xb8\x8e\xe6\xba\x8f\xe6\xbd\xba' width = 10 mode = 'space' diff --git a/urwid/tests/test_util.py b/urwid/tests/test_util.py index 06de8c8..d893eac 100644 --- a/urwid/tests/test_util.py +++ b/urwid/tests/test_util.py @@ -8,6 +8,12 @@ from urwid import util class CalcWidthTest(unittest.TestCase): + def setUp(self) -> None: + self.old_encoding = urwid.util._target_encoding + + def tearDown(self) -> None: + urwid.set_encoding(self.old_encoding) + def wtest(self, desc, s, exp): s = s.encode('iso8859-1') result = util.calc_width( s, 0, len(s)) @@ -29,6 +35,12 @@ class CalcWidthTest(unittest.TestCase): class ConvertDecSpecialTest(unittest.TestCase): + def setUp(self) -> None: + self.old_encoding = urwid.util._target_encoding + + def tearDown(self) -> None: + urwid.set_encoding(self.old_encoding) + def ctest(self, desc, s, exp, expcs): exp = exp.encode('iso8859-1') util.set_encoding('ascii') @@ -51,8 +63,12 @@ class ConvertDecSpecialTest(unittest.TestCase): class WithinDoubleByteTest(unittest.TestCase): def setUp(self): + self.old_encoding = urwid.util._target_encoding urwid.set_encoding("euc-jp") + def tearDown(self) -> None: + urwid.set_encoding(self.old_encoding) + def wtest(self, s, ls, pos, expected, desc): result = util.within_double_byte(s.encode('iso8859-1'), ls, pos) assert result==expected, f"{desc} got:{result!r} expected: {expected!r}" @@ -88,6 +104,12 @@ class WithinDoubleByteTest(unittest.TestCase): class CalcTextPosTest(unittest.TestCase): + def setUp(self) -> None: + self.old_encoding = urwid.util._target_encoding + + def tearDown(self) -> None: + urwid.set_encoding(self.old_encoding) + def ctptest(self, text, tests): text = text.encode('iso8859-1') for s,e,p, expected in tests: diff --git a/urwid/tests/test_widget.py b/urwid/tests/test_widget.py index 4ea2944..9da2abb 100644 --- a/urwid/tests/test_widget.py +++ b/urwid/tests/test_widget.py @@ -1,10 +1,23 @@ from __future__ import annotations +import contextlib import unittest +from collections.abc import Generator import urwid +@contextlib.contextmanager +def encoding(encoding_name: str) -> Generator[None, None, None]: + old_encoding = 'ascii' # Default fallback value + try: + old_encoding = urwid.util._target_encoding + urwid.set_encoding(encoding_name) + yield + finally: + urwid.set_encoding(old_encoding) + + class TextTest(unittest.TestCase): def setUp(self): self.t = urwid.Text("I walk the\ncity in the night") @@ -33,10 +46,10 @@ class TextTest(unittest.TestCase): assert got == expected, f"got: {got!r} expected: {expected!r}" def test5_encode_error(self): - urwid.set_encoding("ascii") - expected = [b"? "] - got = urwid.Text('û').render((3,))._text - assert got == expected, f"got: {got!r} expected: {expected!r}" + with encoding("ascii"): + expected = [b"? "] + got = urwid.Text('û').render((3,))._text + assert got == expected, f"got: {got!r} expected: {expected!r}" class EditTest(unittest.TestCase): @@ -87,12 +100,12 @@ class EditTest(unittest.TestCase): self.ktest(self.t3,'down','down',15,"down at bottom") def test_utf8_input(self): - urwid.set_encoding("utf-8") - self.t1.set_edit_text('') - self.t1.keypress((12,), 'û') - self.assertEqual(self.t1.edit_text, 'û'.encode()) - self.t4.keypress((12,), 'û') - self.assertEqual(self.t4.edit_text, 'û') + with encoding("utf-8"): + self.t1.set_edit_text('') + self.t1.keypress((12,), 'û') + self.assertEqual(self.t1.edit_text, 'û'.encode()) + self.t4.keypress((12,), 'û') + self.assertEqual(self.t4.edit_text, 'û') class EditRenderTest(unittest.TestCase): |