From cf0307c500e1d575fec5fc5a37e4ff4e69972b92 Mon Sep 17 00:00:00 2001 From: Andrew Dunai Date: Thu, 4 Jan 2018 13:56:40 +0200 Subject: Python dual support (#266) * WIP * Metaclasses * String literal fixes * Remove 2to3 and make tests compatible with both Python 2 & 3 * Removed debug code. * Added tests for ProgressBar * Fixed examples. * future division & font literals fix * Cleaner fonts initialization. --- examples/twisted_serve_ssh.py | 6 ++++-- setup.py | 3 --- urwid/__init__.py | 2 ++ urwid/canvas.py | 18 +++++++++------- urwid/command_map.py | 2 ++ urwid/compat.py | 26 ++++++++++++++++++++++ urwid/container.py | 15 +++++++------ urwid/curses_display.py | 12 +++++++---- urwid/decoration.py | 13 +++++------ urwid/display_common.py | 9 ++++---- urwid/escape.py | 2 ++ urwid/font.py | 38 ++++++++++++++++++++------------ urwid/graphics.py | 39 +++++++++++++++++++++++++++++---- urwid/highlight.css | 19 ++++++++++++++++ urwid/html_fragment.py | 16 ++++++++------ urwid/lcd_display.py | 5 +++-- urwid/listbox.py | 45 +++++++++++++++++++------------------- urwid/main_loop.py | 13 +++++------ urwid/monitored_list.py | 20 +++++++++-------- urwid/old_str_util.py | 11 +++++----- urwid/raw_display.py | 7 +++++- urwid/signals.py | 3 ++- urwid/split_repr.py | 8 ++++--- urwid/tests/test_doctests.py | 1 + urwid/tests/test_vterm.py | 2 +- urwid/tests/test_widget.py | 8 +++---- urwid/text_layout.py | 8 ++++--- urwid/treetools.py | 2 ++ urwid/util.py | 10 +++++---- urwid/version.py | 1 + urwid/vterm.py | 4 +++- urwid/web_display.py | 8 +++++-- urwid/widget.py | 50 ++++++++++++++++++++----------------------- urwid/wimp.py | 12 ++++++----- 34 files changed, 285 insertions(+), 153 deletions(-) create mode 100644 urwid/highlight.css diff --git a/examples/twisted_serve_ssh.py b/examples/twisted_serve_ssh.py index 5335646..c1a0004 100644 --- a/examples/twisted_serve_ssh.py +++ b/examples/twisted_serve_ssh.py @@ -200,7 +200,7 @@ class TwistedScreen(Screen): """ return self.terminalProtocol.width, self.terminalProtocol.height - def draw_screen(self, (maxcol, maxrow), r ): + def draw_screen(self, maxres, r ): """Render a canvas to the terminal. The canvas contains all the information required to render the Urwid @@ -208,6 +208,7 @@ class TwistedScreen(Screen): tuples. This very simple implementation iterates each row and simply writes it out. """ + (maxcol, maxrow) = maxres #self.terminal.eraseDisplay() lasta = None for i, row in enumerate(r.content()): @@ -411,9 +412,10 @@ class UrwidTerminalSession(TerminalSession): IConchUser(self.original), self.height, self.width) - def windowChanged(self, (h, w, x, y)): + def windowChanged(self, dimensions): """Called when the window size has changed. """ + (h, w, x, y) = dimensions self.chained_protocol.terminalProtocol.terminalSize(h, w) diff --git a/setup.py b/setup.py index fcb9e5f..37a7413 100644 --- a/setup.py +++ b/setup.py @@ -79,9 +79,6 @@ if have_setuptools: setup_d['zip_safe'] = False setup_d['test_suite'] = 'urwid.tests' -if PYTHON3: - setup_d['use_2to3'] = True - if __name__ == "__main__": try: setup(**setup_d) diff --git a/urwid/__init__.py b/urwid/__init__.py index bc5170e..32484de 100644 --- a/urwid/__init__.py +++ b/urwid/__init__.py @@ -20,6 +20,8 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + from urwid.version import VERSION, __version__ from urwid.widget import (FLOW, BOX, FIXED, LEFT, RIGHT, CENTER, TOP, MIDDLE, BOTTOM, SPACE, ANY, CLIP, PACK, GIVEN, RELATIVE, RELATIVE_100, WEIGHT, diff --git a/urwid/canvas.py b/urwid/canvas.py index 4a51d3e..207ee21 100644 --- a/urwid/canvas.py +++ b/urwid/canvas.py @@ -19,6 +19,8 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + import weakref from urwid.util import rle_len, rle_append_modify, rle_join_modify, rle_product, \ @@ -828,7 +830,7 @@ def shard_body_row(sbody): row = [] for done_rows, content_iter, cview in sbody: if content_iter: - row.extend(content_iter.next()) + row.extend(next(content_iter)) else: # need to skip this unchanged canvas if row and type(row[-1]) == int: @@ -867,10 +869,10 @@ def shards_delta(shards, other_shards): done = other_done = 0 for num_rows, cviews in shards: if other_num_rows is None: - other_num_rows, other_cviews = other_shards_iter.next() + other_num_rows, other_cviews = next(other_shards_iter) while other_done < done: other_done += other_num_rows - other_num_rows, other_cviews = other_shards_iter.next() + other_num_rows, other_cviews = next(other_shards_iter) if other_done > done: yield (num_rows, cviews) done += num_rows @@ -889,10 +891,10 @@ def shard_cviews_delta(cviews, other_cviews): cols = other_cols = 0 for cv in cviews: if other_cv is None: - other_cv = other_cviews_iter.next() + other_cv = next(other_cviews_iter) while other_cols < cols: other_cols += other_cv[2] - other_cv = other_cviews_iter.next() + other_cv = next(other_cviews_iter) if other_cols > cols: yield cv cols += cv[2] @@ -926,7 +928,7 @@ def shard_body(cviews, shard_tail, create_iter=True, iter_default=None): for col_gap, done_rows, content_iter, tail_cview in shard_tail: while col_gap: try: - cview = cviews_iter.next() + cview = next(cviews_iter) except StopIteration: raise CanvasError("cviews do not fill gaps in" " shard_tail!") @@ -1057,7 +1059,7 @@ def shards_join(shard_lists): All shards lists must have the same number of rows. """ shards_iters = [iter(sl) for sl in shard_lists] - shards_current = [i.next() for i in shards_iters] + shards_current = [next(i) for i in shards_iters] new_shards = [] while True: @@ -1078,7 +1080,7 @@ def shards_join(shard_lists): for i in range(len(shards_current)): if shards_current[i][0] > 0: continue - shards_current[i] = shards_iters[i].next() + shards_current[i] = next(shards_iters[i]) except StopIteration: break return new_shards diff --git a/urwid/command_map.py b/urwid/command_map.py index 15633f8..e6965f7 100644 --- a/urwid/command_map.py +++ b/urwid/command_map.py @@ -19,6 +19,8 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + REDRAW_SCREEN = 'redraw screen' CURSOR_UP = 'cursor up' CURSOR_DOWN = 'cursor down' diff --git a/urwid/compat.py b/urwid/compat.py index 686d703..de0bf7a 100644 --- a/urwid/compat.py +++ b/urwid/compat.py @@ -20,6 +20,8 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + import sys try: # python 2.4 and 2.5 compat @@ -39,10 +41,34 @@ if PYTHON3: chr2 = lambda x: bytes([x]) B = lambda x: x.encode('iso8859-1') bytes3 = bytes + text_type = str + xrange = range + text_types = (str,) else: ord2 = ord chr2 = chr B = lambda x: x bytes3 = lambda x: bytes().join([chr(c) for c in x]) + text_type = unicode + xrange = xrange + text_types = (str, unicode) + + +def with_metaclass(meta, *bases): + """ + Create a base class with a metaclass. + Taken from "six" library (https://pythonhosted.org/six/). + """ + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(type): + + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + @classmethod + def __prepare__(cls, name, this_bases): + return meta.__prepare__(name, bases) + return type.__new__(metaclass, 'temporary_class', (), {}) diff --git a/urwid/container.py b/urwid/container.py index 0483482..c2cc71f 100755 --- a/urwid/container.py +++ b/urwid/container.py @@ -19,7 +19,10 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + from itertools import chain, repeat +from urwid.compat import xrange from urwid.util import is_mouse_press from urwid.widget import (Widget, Divider, FLOW, FIXED, PACK, BOX, WidgetWrap, @@ -1589,9 +1592,9 @@ class Pile(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin): return key if self._command_map[key] == 'cursor up': - candidates = range(i-1, -1, -1) # count backwards to 0 + candidates = list(range(i-1, -1, -1)) # count backwards to 0 else: # self._command_map[key] == 'cursor down' - candidates = range(i+1, len(self.contents)) + candidates = list(range(i+1, len(self.contents))) if not item_rows: item_rows = self.get_item_rows(size, focus=True) @@ -1607,9 +1610,9 @@ class Pile(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin): rows = item_rows[j] if self._command_map[key] == 'cursor up': - rowlist = range(rows-1, -1, -1) + rowlist = list(range(rows-1, -1, -1)) else: # self._command_map[key] == 'cursor down' - rowlist = range(rows) + rowlist = list(range(rows)) for row in rowlist: tsize = self.get_item_size(size, j, True, item_rows) if self.focus_item.move_cursor_to_coords( @@ -2272,9 +2275,9 @@ class Columns(Widget, WidgetContainerMixin, WidgetContainerListContentsMixin): return key if self._command_map[key] == 'cursor left': - candidates = range(i-1, -1, -1) # count backwards to 0 + candidates = list(range(i-1, -1, -1)) # count backwards to 0 else: # key == 'right' - candidates = range(i+1, len(self.contents)) + candidates = list(range(i+1, len(self.contents))) for j in candidates: if not self.contents[j][0].selectable(): diff --git a/urwid/curses_display.py b/urwid/curses_display.py index 441042e..0aaa2f1 100755 --- a/urwid/curses_display.py +++ b/urwid/curses_display.py @@ -19,6 +19,8 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + """ Curses-based UI implementation """ @@ -30,7 +32,7 @@ from urwid import escape from urwid.display_common import BaseScreen, RealTerminal, AttrSpec, \ UNPRINTABLE_TRANS_TABLE -from urwid.compat import bytes, PYTHON3 +from urwid.compat import bytes, PYTHON3, text_type, xrange KEY_RESIZE = 410 # curses.KEY_RESIZE (sometimes not defined) KEY_MOUSE = 409 # curses.KEY_MOUSE @@ -481,10 +483,12 @@ class Screen(BaseScreen, RealTerminal): self.s.attrset(attr) - def draw_screen(self, (cols, rows), r ): + def draw_screen(self, size, r ): """Paint screen with rendered canvas.""" assert self._started + cols, rows = size + assert r.rows() == rows, "canvas size and passed size don't match" y = -1 @@ -558,7 +562,7 @@ class Screen(BaseScreen, RealTerminal): class _test: def __init__(self): self.ui = Screen() - self.l = _curses_colours.keys() + self.l = list(_curses_colours.keys()) self.l.sort() for c in self.l: self.ui.register_palette( [ @@ -602,7 +606,7 @@ class _test: t = "" a = [] for k in keys: - if type(k) == unicode: k = k.encode("utf-8") + if type(k) == text_type: k = k.encode("utf-8") t += "'"+k + "' " a += [(None,1), ('yellow on dark blue',len(k)), (None,2)] diff --git a/urwid/decoration.py b/urwid/decoration.py index 731eb91..978722f 100755 --- a/urwid/decoration.py +++ b/urwid/decoration.py @@ -19,6 +19,7 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function from urwid.util import int_scale from urwid.widget import (Widget, WidgetError, @@ -129,14 +130,14 @@ class AttrMap(delegate_to_widget_mixin('_original_widget'), WidgetDecoration): attr_map={None: 'notfocus'} focus_map={None: 'focus'}> >>> size = (5,) >>> am = AttrMap(Text(u"hi"), 'greeting', 'fgreet') - >>> am.render(size, focus=False).content().next() # ... = b in Python 3 + >>> next(am.render(size, focus=False).content()) # ... = b in Python 3 [('greeting', None, ...'hi ')] - >>> am.render(size, focus=True).content().next() + >>> next(am.render(size, focus=True).content()) [('fgreet', None, ...'hi ')] >>> am2 = AttrMap(Text(('word', u"hi")), {'word':'greeting', None:'bg'}) >>> am2 attr_map={'word': 'greeting', None: 'bg'}> - >>> am2.render(size).content().next() + >>> next(am2.render(size).content()) [('greeting', None, ...'hi'), ('bg', None, ...' ')] """ self.__super.__init__(w) @@ -247,9 +248,9 @@ class AttrWrap(AttrMap): attr='notfocus' focus_attr='focus'> >>> size = (5,) >>> aw = AttrWrap(Text(u"hi"), 'greeting', 'fgreet') - >>> aw.render(size, focus=False).content().next() + >>> next(aw.render(size, focus=False).content()) [('greeting', None, ...'hi ')] - >>> aw.render(size, focus=True).content().next() + >>> next(aw.render(size, focus=True).content()) [('fgreet', None, ...'hi ')] """ self.__super.__init__(w, attr, focus_attr) @@ -460,7 +461,7 @@ class Padding(WidgetDecoration): >>> size = (7,) >>> def pr(w): ... for t in w.render(size).text: - ... print "|%s|" % (t.decode('ascii'),) + ... print("|%s|" % (t.decode('ascii'),)) >>> pr(Padding(Text(u"Head"), ('relative', 20), 'pack')) | Head | >>> pr(Padding(Divider(u"-"), left=2, right=1)) diff --git a/urwid/display_common.py b/urwid/display_common.py index 26f3a5a..e447682 100755 --- a/urwid/display_common.py +++ b/urwid/display_common.py @@ -18,6 +18,8 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + import os import sys @@ -28,10 +30,10 @@ except ImportError: from urwid.util import StoppingContext, int_scale from urwid import signals -from urwid.compat import B, bytes3 +from urwid.compat import B, bytes3, xrange, with_metaclass # for replacing unprintable bytes with '?' -UNPRINTABLE_TRANS_TABLE = B("?") * 32 + bytes3(range(32,256)) +UNPRINTABLE_TRANS_TABLE = B("?") * 32 + bytes3(list(xrange(32,256))) # signals sent by BaseScreen @@ -719,11 +721,10 @@ class RealTerminal(object): class ScreenError(Exception): pass -class BaseScreen(object): +class BaseScreen(with_metaclass(signals.MetaSignals, object)): """ Base class for Screen classes (raw_display.Screen, .. etc) """ - __metaclass__ = signals.MetaSignals signals = [UPDATE_PALETTE_ENTRY, INPUT_DESCRIPTORS_CHANGED] def __init__(self): diff --git a/urwid/escape.py b/urwid/escape.py index 683466c..b047fb0 100644 --- a/urwid/escape.py +++ b/urwid/escape.py @@ -20,6 +20,8 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + """ Terminal Escape Sequences for input and display """ diff --git a/urwid/font.py b/urwid/font.py index bf0c2b1..e7bfe6e 100755 --- a/urwid/font.py +++ b/urwid/font.py @@ -20,9 +20,12 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + from urwid.escape import SAFE_ASCII_DEC_SPECIAL_RE from urwid.util import apply_target_encoding, str_util from urwid.canvas import TextCanvas +from urwid.compat import text_type def separate_glyphs(gdata, height): @@ -96,9 +99,16 @@ class Font(object): self.char = {} self.canvas = {} self.utf8_required = False - for gdata in self.data: + data = [self._to_text(block) for block in self.data] + for gdata in data: self.add_glyphs(gdata) + @staticmethod + def _to_text(obj, encoding='utf-8', errors='strict'): + if isinstance(obj, text_type): + return obj + elif isinstance(obj, bytes): + return obj.decode(encoding, errors) def add_glyphs(self, gdata): d, utf8_required = separate_glyphs(gdata, self.height) @@ -106,7 +116,7 @@ class Font(object): self.utf8_required |= utf8_required def characters(self): - l = self.char.keys() + l = list(self.char.keys()) l.sort() return "".join(l) @@ -147,7 +157,7 @@ class Thin3x3Font(Font): ┌─┐ ┐ ┌─┐┌─┐ ┐┌─ ┌─ ┌─┐┌─┐┌─┐ │ │ │ │ ┌─┘ ─┤└─┼└─┐├─┐ ┼├─┤└─┤ │ └─┘ ┴ └─ └─┘ ┴ ─┘└─┘ ┴└─┘ ─┘ . -""", ur""" +""", r""" "###$$$%%%'*++,--.///:;==???[[\\\]]^__` " ┼┼┌┼┐O /' /.. _┌─┐┌ \ ┐^ ` ┼┼└┼┐ / * ┼ ─ / ., _ ┌┘│ \ │ @@ -179,7 +189,7 @@ class HalfBlock5x4Font(Font): ▀█▀█▀ ▀▄█▄ █ ▀▄▀ ▐▌ ▐▌ ▄▄█▄▄ ▄▄█▄▄ ▄▄▄▄ █ ▀ ▀ ▀█▀█▀ ▄ █ █ ▐▌▄ █ ▀▄▌▐▌ ▐▌ ▄▀▄ █ ▐▌ ▀ ▄▀ ▀ ▀ ▀▀▀ ▀ ▀ ▀▀ ▀ ▀ ▄▀ ▀ ▀ -''', ur""" +''', r""" <<<<<=====>>>>>?????@@@@@@[[[[\\\\]]]]^^^^____```{{{{||}}}}~~~~''´´´ ▄▀ ▀▄ ▄▀▀▄ ▄▀▀▀▄ █▀▀ ▐▌ ▀▀█ ▄▀▄ ▀▄ ▄▀ █ ▀▄ ▄ █ ▄▀ ▄▀ ▀▀▀▀ ▀▄ ▄▀ █ █▀█ █ █ █ ▄▀ █ ▀▄ ▐▐▌▌ @@ -258,7 +268,7 @@ class Thin6x6Font(Font): │ │ │ │ │ │ │ │ │ │ │ │ │ └───┘ ┴ └─── └───┘ ┴ ───┘ └───┘ ┴ └───┘ ───┘ -""", ur''' +""", r''' !! """######$$$$$$%%%%%%&&&&&&((()))******++++++ │ ││ ┌ ┌ ┌─┼─┐ ┌┐ / ┌─┐ / \ │ ─┼─┼─ │ │ └┘ / │ │ │ │ \ / │ @@ -266,7 +276,7 @@ class Thin6x6Font(Font): │ ─┼─┼─ │ │ / ┌┐ │ \, │ │ / \ │ . ┘ ┘ └─┼─┘ / └┘ └───\ \ / -''', ur""" +''', r""" ,,-----..//////::;;<<<<=====>>>>??????@@@@@@ / ┌───┐ ┌───┐ / . . / ──── \ │ │┌──┤ @@ -274,7 +284,7 @@ class Thin6x6Font(Font): / . , \ ──── / │ │└──┘ , . / \ / . └───┘ -""", ur""" +""", r""" [[\\\\\\]]^^^____``{{||}}~~~~~~ ┌ \ ┐ /\ \ ┌ │ ┐ │ \ │ │ │ │ ┌─┐ @@ -363,7 +373,7 @@ class HalfBlock7x7Font(Font): █▌ ▀ ▀█▌ ▐█▀ ▐█ ▀▀▀ ▐█ ▐█ ▐█ █▌ ▀███▀ ▀ -""", ur""" +""", r""" [[[[\\\\\]]]]^^^^^^^_____```{{{{{|||}}}}}~~~~~~~´´´ ▐██▌▐█ ▐██▌ ▐█▌ ▐█ █▌▐█ ▐█ █▌ ▐█ █▌ █▌ ▐█ █▌ █▌ █▌ ▐█ ▐█ ▄▄ ▐█ @@ -433,18 +443,18 @@ add_font("Half Block 7x7",HalfBlock7x7Font) if __name__ == "__main__": l = get_all_fonts() all_ascii = "".join([chr(x) for x in range(32, 127)]) - print "Available Fonts: (U) = UTF-8 required" - print "----------------" + print("Available Fonts: (U) = UTF-8 required") + print("----------------") for n,cls in l: f = cls() u = "" if f.utf8_required: u = "(U)" - print ("%-20s %3s " % (n,u)), + print(("%-20s %3s " % (n,u)), end=' ') c = f.characters() if c == all_ascii: - print "Full ASCII" + print("Full ASCII") elif c.startswith(all_ascii): - print "Full ASCII + " + c[len(all_ascii):] + print("Full ASCII + " + c[len(all_ascii):]) else: - print "Characters: " + c + print("Characters: " + c) diff --git a/urwid/graphics.py b/urwid/graphics.py index cb852b0..a40f1ba 100755 --- a/urwid/graphics.py +++ b/urwid/graphics.py @@ -20,6 +20,9 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + +from urwid.compat import with_metaclass from urwid.util import decompose_tagmarkup, get_encoding_mode from urwid.canvas import CompositeCanvas, CanvasJoin, TextCanvas, \ CanvasCombine, SolidCanvas @@ -192,9 +195,7 @@ def nocache_bargraph_get_data(self, get_data_fn): class BarGraphError(Exception): pass -class BarGraph(Widget): - __metaclass__ = BarGraphMeta - +class BarGraph(with_metaclass(BarGraphMeta, Widget)): _sizing = frozenset([BOX]) ignore_focus = True @@ -481,7 +482,8 @@ class BarGraph(Widget): o = [] r = 0 # row remainder - def seg_combine((bt1, w1), (bt2, w2)): + def seg_combine(a, b): + (bt1, w1), (bt2, w2) = a, b if (bt1, w1) == (bt2, w2): return (bt1, w1), None, None wmin = min(w1, w2) @@ -811,6 +813,28 @@ class ProgressBar(Widget): foreground of satt corresponds to the normal part and the background corresponds to the complete part. If satt is ``None`` then no smoothing will be done. + + >>> pb = ProgressBar('a', 'b') + >>> pb + + >>> print(pb.get_text()) + 0 % + >>> pb.set_completion(34.42) + >>> print(pb.get_text()) + 34 % + >>> class CustomProgressBar(ProgressBar): + ... def get_text(self): + ... return u'Foobar' + >>> cpb = CustomProgressBar('a', 'b') + >>> print(cpb.get_text()) + Foobar + >>> for x in range(101): + ... cpb.set_completion(x) + ... s = cpb.render((10, )) + >>> cpb2 = CustomProgressBar('a', 'b', satt='c') + >>> for x in range(101): + ... cpb2.set_completion(x) + ... s = cpb2.render((10, )) """ self.normal = normal self.complete = complete @@ -915,3 +939,10 @@ class PythonLogo(Widget): """ fixed_size(size) return self._canvas + +def _test(): + import doctest + doctest.testmod() + +if __name__=='__main__': + _test() diff --git a/urwid/highlight.css b/urwid/highlight.css new file mode 100644 index 0000000..097663d --- /dev/null +++ b/urwid/highlight.css @@ -0,0 +1,19 @@ +/* Style definition file generated by highlight 3.41, http://www.andre-simon.de/ */ +/* highlight theme: Kwrite Editor */ +body.hl { background-color:#e0eaee; } +pre.hl { color:#000000; background-color:#e0eaee; font-size:10pt; font-family:'Courier New',monospace;} +.hl.num { color:#b07e00; } +.hl.esc { color:#ff00ff; } +.hl.str { color:#bf0303; } +.hl.pps { color:#818100; } +.hl.slc { color:#838183; font-style:italic; } +.hl.com { color:#838183; font-style:italic; } +.hl.ppc { color:#008200; } +.hl.opt { color:#000000; } +.hl.ipl { color:#0057ae; } +.hl.lin { color:#555555; } +.hl.kwa { color:#000000; font-weight:bold; } +.hl.kwb { color:#0057ae; } +.hl.kwc { color:#000000; font-weight:bold; } +.hl.kwd { color:#010181; } + diff --git a/urwid/html_fragment.py b/urwid/html_fragment.py index 3db1fd9..5df9273 100755 --- a/urwid/html_fragment.py +++ b/urwid/html_fragment.py @@ -19,6 +19,8 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + """ HTML PRE-based UI implementation """ @@ -76,13 +78,15 @@ class HtmlGenerator(BaseScreen): def reset_default_terminal_palette(self, *args): pass - def draw_screen(self, (cols, rows), r ): + def draw_screen(self, size, r ): """Create an html fragment from the render object. Append it to HtmlGenerator.fragments list. """ # collect output in l l = [] + cols, rows = size + assert r.rows() == rows if r.cursor is not None: @@ -134,7 +138,7 @@ class HtmlGenerator(BaseScreen): def get_cols_rows(self): """Return the next screen size in HtmlGenerator.sizes.""" if not self.sizes: - raise HtmlGeneratorSimulationError, "Ran out of screen sizes to return!" + raise HtmlGeneratorSimulationError("Ran out of screen sizes to return!") return self.sizes.pop(0) def get_input(self, raw_keys=False): @@ -219,7 +223,7 @@ def screenshot_init( sizes, keys ): assert type(row) == int assert row>0 and col>0 except (AssertionError, ValueError): - raise Exception, "sizes must be in the form [ (col1,row1), (col2,row2), ...]" + raise Exception("sizes must be in the form [ (col1,row1), (col2,row2), ...]") try: for l in keys: @@ -227,11 +231,11 @@ def screenshot_init( sizes, keys ): for k in l: assert type(k) == str except (AssertionError, ValueError): - raise Exception, "keys must be in the form [ [keyA1, keyA2, ..], [keyB1, ..], ...]" + raise Exception("keys must be in the form [ [keyA1, keyA2, ..], [keyB1, ..], ...]") - import curses_display + from . import curses_display curses_display.Screen = HtmlGenerator - import raw_display + from . import raw_display raw_display.Screen = HtmlGenerator HtmlGenerator.sizes = sizes diff --git a/urwid/lcd_display.py b/urwid/lcd_display.py index 4f62173..e189d9a 100644 --- a/urwid/lcd_display.py +++ b/urwid/lcd_display.py @@ -20,8 +20,9 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function -from display_common import BaseScreen +from .display_common import BaseScreen import time @@ -39,7 +40,7 @@ class LCDScreen(BaseScreen): def reset_default_terminal_palette(self, *args): pass - def draw_screen(self, (cols, rows), r ): + def draw_screen(self, size, r ): pass def clear(self): diff --git a/urwid/listbox.py b/urwid/listbox.py index 0a65afa..802b1d6 100644 --- a/urwid/listbox.py +++ b/urwid/listbox.py @@ -19,6 +19,9 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + +from urwid.compat import xrange, with_metaclass from urwid.util import is_mouse_press from urwid.canvas import SolidCanvas, CanvasCombine from urwid.widget import Widget, nocache_widget_render_instance, BOX, GIVEN @@ -33,9 +36,7 @@ from urwid.command_map import (CURSOR_UP, CURSOR_DOWN, class ListWalkerError(Exception): pass -class ListWalker(object): - __metaclass__ = signals.MetaSignals - +class ListWalker(with_metaclass(signals.MetaSignals, object)): signals = ["modified"] def _modified(self): @@ -141,7 +142,7 @@ class SimpleListWalker(MonitoredList, ListWalker): this list walker to be updated. """ if not getattr(contents, '__getitem__', None): - raise ListWalkerError, "SimpleListWalker expecting list like object, got: %r"%(contents,) + raise ListWalkerError("SimpleListWalker expecting list like object, got: %r"%(contents,)) MonitoredList.__init__(self, contents) self.focus = 0 @@ -175,7 +176,7 @@ class SimpleListWalker(MonitoredList, ListWalker): if position < 0 or position >= len(self): raise ValueError except (TypeError, ValueError): - raise IndexError, "No widget at position %s" % (position,) + raise IndexError("No widget at position %s" % (position,)) self.focus = position self._modified() @@ -481,17 +482,17 @@ class ListBox(Widget, WidgetContainerMixin): for widget,w_pos,w_rows in fill_above: canvas = widget.render((maxcol,)) if w_rows != canvas.rows(): - raise ListBoxError, "Widget %r at position %r within listbox calculated %d rows but rendered %d!"% (widget,w_pos,w_rows, canvas.rows()) + raise ListBoxError("Widget %r at position %r within listbox calculated %d rows but rendered %d!"% (widget,w_pos,w_rows, canvas.rows())) rows += w_rows combinelist.append((canvas, w_pos, False)) focus_canvas = focus_widget.render((maxcol,), focus=focus) if focus_canvas.rows() != focus_rows: - raise ListBoxError, "Focus Widget %r at position %r within listbox calculated %d rows but rendered %d!"% (focus_widget,focus_pos,focus_rows, focus_canvas.rows()) + raise ListBoxError("Focus Widget %r at position %r within listbox calculated %d rows but rendered %d!"% (focus_widget,focus_pos,focus_rows, focus_canvas.rows())) c_cursor = focus_canvas.cursor if cursor != c_cursor: - raise ListBoxError, "Focus Widget %r at position %r within listbox calculated cursor coords %r but rendered cursor coords %r!" %(focus_widget,focus_pos,cursor,c_cursor) + raise ListBoxError("Focus Widget %r at position %r within listbox calculated cursor coords %r but rendered cursor coords %r!" %(focus_widget,focus_pos,cursor,c_cursor)) rows += focus_rows combinelist.append((focus_canvas, focus_pos, True)) @@ -499,7 +500,7 @@ class ListBox(Widget, WidgetContainerMixin): for widget,w_pos,w_rows in fill_below: canvas = widget.render((maxcol,)) if w_rows != canvas.rows(): - raise ListBoxError, "Widget %r at position %r within listbox calculated %d rows but rendered %d!"% (widget,w_pos,w_rows, canvas.rows()) + raise ListBoxError("Widget %r at position %r within listbox calculated %d rows but rendered %d!"% (widget,w_pos,w_rows, canvas.rows())) rows += w_rows combinelist.append((canvas, w_pos, False)) @@ -513,13 +514,13 @@ class ListBox(Widget, WidgetContainerMixin): rows -= trim_bottom if rows > maxrow: - raise ListBoxError, "Listbox contents too long! Probably urwid's fault (please report): %r" % ((top,middle,bottom),) + raise ListBoxError("Listbox contents too long! Probably urwid's fault (please report): %r" % ((top,middle,bottom),)) if rows < maxrow: bottom_pos = focus_pos if fill_below: bottom_pos = fill_below[-1][1] if trim_bottom != 0 or self._body.get_next(bottom_pos) != (None,None): - raise ListBoxError, "Listbox contents too short! Probably urwid's fault (please report): %r" % ((top,middle,bottom),) + raise ListBoxError("Listbox contents too short! Probably urwid's fault (please report): %r" % ((top,middle,bottom),)) final_canvas.pad_trim_top_bottom(0, maxrow - rows) return final_canvas @@ -603,7 +604,7 @@ class ListBox(Widget, WidgetContainerMixin): """ w, pos = self._body.get_focus() if w is None: - raise IndexError, "No focus_position, ListBox is empty" + raise IndexError("No focus_position, ListBox is empty") return pos focus_position = property(_get_focus_position, set_focus, doc=""" the position of child widget in focus. The valid values for this @@ -785,14 +786,14 @@ class ListBox(Widget, WidgetContainerMixin): if offset_inset >= 0: if offset_inset >= maxrow: - raise ListBoxError, "Invalid offset_inset: %r, only %r rows in list box"% (offset_inset, maxrow) + raise ListBoxError("Invalid offset_inset: %r, only %r rows in list box"% (offset_inset, maxrow)) self.offset_rows = offset_inset self.inset_fraction = (0,1) else: target, _ignore = self._body.get_focus() tgt_rows = target.rows( (maxcol,), True ) if offset_inset + tgt_rows <= 0: - raise ListBoxError, "Invalid offset_inset: %r, only %r rows in target!" %(offset_inset, tgt_rows) + raise ListBoxError("Invalid offset_inset: %r, only %r rows in target!" %(offset_inset, tgt_rows)) self.offset_rows = 0 self.inset_fraction = (-offset_inset,tgt_rows) self._invalidate() @@ -889,7 +890,7 @@ class ListBox(Widget, WidgetContainerMixin): self.inset_fraction = (0,1) else: if offset_inset + tgt_rows <= 0: - raise ListBoxError, "Invalid offset_inset: %s, only %s rows in target!" %(offset_inset, tgt_rows) + raise ListBoxError("Invalid offset_inset: %s, only %s rows in target!" %(offset_inset, tgt_rows)) self.offset_rows = 0 self.inset_fraction = (-offset_inset,tgt_rows) @@ -917,7 +918,7 @@ class ListBox(Widget, WidgetContainerMixin): # start from preferred row and move back to closest edge (pref_col, pref_row) = cursor_coords if pref_row < 0 or pref_row >= tgt_rows: - raise ListBoxError, "cursor_coords row outside valid range for target. pref_row:%r target_rows:%r"%(pref_row,tgt_rows) + raise ListBoxError("cursor_coords row outside valid range for target. pref_row:%r target_rows:%r"%(pref_row,tgt_rows)) if coming_from=='above': attempt_rows = range( pref_row, -1, -1 ) @@ -940,10 +941,10 @@ class ListBox(Widget, WidgetContainerMixin): if offset_rows == 0: inum, iden = self.inset_fraction if inum < 0 or iden < 0 or inum >= iden: - raise ListBoxError, "Invalid inset_fraction: %r"%(self.inset_fraction,) + raise ListBoxError("Invalid inset_fraction: %r"%(self.inset_fraction,)) inset_rows = focus_rows * inum // iden if inset_rows and inset_rows >= focus_rows: - raise ListBoxError, "urwid inset_fraction error (please report)" + raise ListBoxError("urwid inset_fraction error (please report)") return offset_rows, inset_rows @@ -1272,8 +1273,8 @@ class ListBox(Widget, WidgetContainerMixin): # choose the topmost selectable and (newly) visible widget # search within snap_rows then visible region - search_order = ( range( snap_region_start, len(t)) - + range( snap_region_start-1, -1, -1 ) ) + search_order = (list(xrange(snap_region_start, len(t))) + + list(xrange(snap_region_start-1, -1, -1))) #assert 0, repr((t, search_order)) bad_choices = [] cut_off_selectable_chosen = 0 @@ -1457,8 +1458,8 @@ class ListBox(Widget, WidgetContainerMixin): # choose the bottommost selectable and (newly) visible widget # search within snap_rows then visible region - search_order = ( range( snap_region_start, len(t)) - + range( snap_region_start-1, -1, -1 ) ) + search_order = (list(xrange(snap_region_start, len(t))) + + list(xrange(snap_region_start-1, -1, -1))) #assert 0, repr((t, search_order)) bad_choices = [] cut_off_selectable_chosen = 0 diff --git a/urwid/main_loop.py b/urwid/main_loop.py index ec9c411..442c27d 100755 --- a/urwid/main_loop.py +++ b/urwid/main_loop.py @@ -21,6 +21,7 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function import time import heapq @@ -694,7 +695,7 @@ class SelectEventLoop(object): """ A single iteration of the event loop """ - fds = self._watch_files.keys() + fds = list(self._watch_files.keys()) if self._alarms or self._did_something: if self._alarms: tm = self._alarms[0][0] @@ -851,7 +852,7 @@ class GLibEventLoop(object): # An exception caused us to exit, raise it now exc_info = self._exc_info self._exc_info = None - raise exc_info[0], exc_info[1], exc_info[2] + raise exc_info[0](exc_info[1]).with_traceback(exc_info[2]) def handle_exit(self,f): """ @@ -1186,7 +1187,7 @@ class TwistedEventLoop(object): # An exception caused us to exit, raise it now exc_info = self._exc_info self._exc_info = None - raise exc_info[0], exc_info[1], exc_info[2] + raise exc_info[0](exc_info[1]).with_traceback(exc_info[2]) def handle_exit(self, f, enable_idle=True): """ @@ -1206,7 +1207,7 @@ class TwistedEventLoop(object): self.reactor.stop() except: import sys - print sys.exc_info() + print(sys.exc_info()) self._exc_info = sys.exc_info() if self.manage_reactor: self.reactor.crash() @@ -1328,7 +1329,7 @@ class AsyncioEventLoop(object): self._loop.set_exception_handler(self._exception_handler) self._loop.run_forever() if self._exc_info: - raise self._exc_info[0], self._exc_info[1], self._exc_info[2] + raise self._exc_info[0](self._exc_info[1]).with_traceback(self._exc_info[2]) self._exc_info = None @@ -1357,7 +1358,7 @@ def _refl(name, rval=None, exit=False): if args and argd: args = args + ", " args = args + ", ".join([k+"="+repr(v) for k,v in argd.items()]) - print self._name+"("+args+")" + print(self._name+"("+args+")") if exit: raise ExitMainLoop() return self._rval diff --git a/urwid/monitored_list.py b/urwid/monitored_list.py index dc67c84..c159064 100755 --- a/urwid/monitored_list.py +++ b/urwid/monitored_list.py @@ -19,7 +19,9 @@ # # Urwid web site: http://excess.org/urwid/ -from urwid.compat import PYTHON3 +from __future__ import division, print_function + +from urwid.compat import PYTHON3, xrange def _call_modified(fn): @@ -238,7 +240,7 @@ class MonitoredFocusList(MonitoredList): """ num_new_items = len(new_items) start, stop, step = indices = slc.indices(len(self)) - num_removed = len(range(*indices)) + num_removed = len(list(xrange(*indices))) focus = self._validate_contents_modified(indices, new_items) if focus is not None: @@ -255,11 +257,11 @@ class MonitoredFocusList(MonitoredList): else: if not num_new_items: # extended slice being removed - if focus in range(start, stop, step): + if focus in xrange(start, stop, step): focus += 1 # adjust for removed items - focus -= len(range(start, min(focus, stop), step)) + focus -= len(list(xrange(start, min(focus, stop), step))) return min(focus, len(self) + num_new_items - num_removed -1) @@ -303,7 +305,7 @@ class MonitoredFocusList(MonitoredList): def __setitem__(self, i, y): """ >>> def modified(indices, new_items): - ... print "range%r <- %r" % (indices, new_items) + ... print("range%r <- %r" % (indices, new_items)) >>> ml = MonitoredFocusList([0,1,2,3], focus=2) >>> ml.set_validate_contents_modified(modified) >>> ml[0] = 9 @@ -347,7 +349,7 @@ class MonitoredFocusList(MonitoredList): def __imul__(self, n): """ >>> def modified(indices, new_items): - ... print "range%r <- %r" % (indices, list(new_items)) + ... print("range%r <- %r" % (indices, list(new_items))) >>> ml = MonitoredFocusList([0,1,2], focus=2) >>> ml.set_validate_contents_modified(modified) >>> ml *= 3 @@ -356,7 +358,7 @@ class MonitoredFocusList(MonitoredList): MonitoredFocusList([0, 1, 2, 0, 1, 2, 0, 1, 2], focus=2) >>> ml *= 0 range(0, 9, 1) <- [] - >>> print ml.focus + >>> print(ml.focus) None """ if n > 0: @@ -371,7 +373,7 @@ class MonitoredFocusList(MonitoredList): def append(self, item): """ >>> def modified(indices, new_items): - ... print "range%r <- %r" % (indices, new_items) + ... print("range%r <- %r" % (indices, new_items)) >>> ml = MonitoredFocusList([0,1,2], focus=2) >>> ml.set_validate_contents_modified(modified) >>> ml.append(6) @@ -386,7 +388,7 @@ class MonitoredFocusList(MonitoredList): def extend(self, items): """ >>> def modified(indices, new_items): - ... print "range%r <- %r" % (indices, list(new_items)) + ... print("range%r <- %r" % (indices, list(new_items))) >>> ml = MonitoredFocusList([0,1,2], focus=2) >>> ml.set_validate_contents_modified(modified) >>> ml.extend((6,7,8)) diff --git a/urwid/old_str_util.py b/urwid/old_str_util.py index 83190f5..2c6d1e0 100755 --- a/urwid/old_str_util.py +++ b/urwid/old_str_util.py @@ -19,11 +19,12 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Urwid web site: http://excess.org/urwid/ -from __future__ import print_function + +from __future__ import division, print_function import re -from urwid.compat import bytes, B, ord2 +from urwid.compat import bytes, B, ord2, text_type SAFE_ASCII_RE = re.compile(u"^[ -~]*$") SAFE_ASCII_BYTES_RE = re.compile(B("^[ -~]*$")) @@ -241,7 +242,7 @@ def is_wide_char(text, offs): text may be unicode or a byte string in the target _byte_encoding """ - if isinstance(text, unicode): + if isinstance(text, text_type): o = ord(text[offs]) return get_width(o) == 2 assert isinstance(text, bytes) @@ -257,7 +258,7 @@ def move_prev_char(text, start_offs, end_offs): Return the position of the character before end_offs. """ assert start_offs < end_offs - if isinstance(text, unicode): + if isinstance(text, text_type): return end_offs-1 assert isinstance(text, bytes) if _byte_encoding == "utf8": @@ -275,7 +276,7 @@ def move_next_char(text, start_offs, end_offs): Return the position of the character after start_offs. """ assert start_offs < end_offs - if isinstance(text, unicode): + if isinstance(text, text_type): return start_offs+1 assert isinstance(text, bytes) if _byte_encoding == "utf8": diff --git a/urwid/raw_display.py b/urwid/raw_display.py index b619d82..9eadc0e 100644 --- a/urwid/raw_display.py +++ b/urwid/raw_display.py @@ -19,6 +19,8 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + """ Direct terminal UI implementation """ @@ -665,8 +667,11 @@ class Screen(BaseScreen, RealTerminal): self._setup_G1_done = True - def draw_screen(self, (maxcol, maxrow), r ): + def draw_screen(self, maxres, r ): """Paint screen with rendered canvas.""" + + (maxcol, maxrow) = maxres + assert self._started assert maxrow == r.rows() diff --git a/urwid/signals.py b/urwid/signals.py index 9e93597..0269dfd 100644 --- a/urwid/signals.py +++ b/urwid/signals.py @@ -19,6 +19,7 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function import itertools import weakref @@ -33,7 +34,7 @@ class MetaSignals(type): signals = d.get("signals", []) for superclass in cls.__bases__: signals.extend(getattr(superclass, 'signals', [])) - signals = dict([(x,None) for x in signals]).keys() + signals = list(dict([(x,None) for x in signals]).keys()) d["signals"] = signals register_signal(cls, signals) super(MetaSignals, cls).__init__(name, bases, d) diff --git a/urwid/split_repr.py b/urwid/split_repr.py index fb108b5..3d7cbeb 100755 --- a/urwid/split_repr.py +++ b/urwid/split_repr.py @@ -19,6 +19,8 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + from inspect import getargspec from urwid.compat import PYTHON3, bytes @@ -129,12 +131,12 @@ def remove_defaults(d, fn): del args[-1] # create a dictionary of args with default values - ddict = dict(zip(args[len(args) - len(defaults):], defaults)) + ddict = dict(list(zip(args[len(args) - len(defaults):], defaults))) - for k, v in d.items(): + for k in list(d.keys()): if k in ddict: # remove values that match their defaults - if ddict[k] == v: + if ddict[k] == d[k]: del d[k] return d diff --git a/urwid/tests/test_doctests.py b/urwid/tests/test_doctests.py index 1720a48..611baf3 100644 --- a/urwid/tests/test_doctests.py +++ b/urwid/tests/test_doctests.py @@ -15,6 +15,7 @@ def load_tests(loader, tests, ignore): 'urwid.split_repr', # override function with same name urwid.util, urwid.signals, + urwid.graphics, ] for m in module_doctests: tests.addTests(doctest.DocTestSuite(m, diff --git a/urwid/tests/test_vterm.py b/urwid/tests/test_vterm.py index 075c653..e47398c 100644 --- a/urwid/tests/test_vterm.py +++ b/urwid/tests/test_vterm.py @@ -191,7 +191,7 @@ class TermTest(unittest.TestCase): self.edgewall() self.expect('1-' + ' ' * 76 + '-2' + '\n' * 22 + '3-' + ' ' * 76 + '-4') - for y in xrange(23, 1, -1): + for y in range(23, 1, -1): self.resize(80, y, soft=True) self.write('\e[%df\e[J3-\e[%d;%df-4' % (y, y, 79)) desc = "try to rescale to 80x%d." % y diff --git a/urwid/tests/test_widget.py b/urwid/tests/test_widget.py index cc8c63e..3f28bc1 100644 --- a/urwid/tests/test_widget.py +++ b/urwid/tests/test_widget.py @@ -10,25 +10,25 @@ class TextTest(unittest.TestCase): self.t = urwid.Text("I walk the\ncity in the night") def test1_wrap(self): - expected = [B(t) for t in "I walk the","city in ","the night "] + expected = [B(t) for t in ("I walk the","city in ","the night ")] got = self.t.render((10,))._text assert got == expected, "got: %r expected: %r" % (got, expected) def test2_left(self): self.t.set_align_mode('left') - expected = [B(t) for t in "I walk the ","city in the night "] + expected = [B(t) for t in ("I walk the ","city in the night ")] got = self.t.render((18,))._text assert got == expected, "got: %r expected: %r" % (got, expected) def test3_right(self): self.t.set_align_mode('right') - expected = [B(t) for t in " I walk the"," city in the night"] + expected = [B(t) for t in (" I walk the"," city in the night")] got = self.t.render((18,))._text assert got == expected, "got: %r expected: %r" % (got, expected) def test4_center(self): self.t.set_align_mode('center') - expected = [B(t) for t in " I walk the "," city in the night"] + expected = [B(t) for t in (" I walk the "," city in the night")] got = self.t.render((18,))._text assert got == expected, "got: %r expected: %r" % (got, expected) diff --git a/urwid/text_layout.py b/urwid/text_layout.py index f09372b..d8663b6 100644 --- a/urwid/text_layout.py +++ b/urwid/text_layout.py @@ -19,9 +19,11 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + from urwid.util import calc_width, calc_text_pos, calc_trim_text, is_wide_char, \ move_prev_char, move_next_char -from urwid.compat import bytes, PYTHON3, B +from urwid.compat import bytes, PYTHON3, B, xrange class TextLayout: def supports_align_mode(self, align): @@ -456,8 +458,8 @@ def calc_pos( text, layout, pref_col, row ): if pos is not None: return pos - rows_above = range(row-1,-1,-1) - rows_below = range(row+1,len(layout)) + rows_above = list(xrange(row-1,-1,-1)) + rows_below = list(xrange(row+1,len(layout))) while rows_above and rows_below: if rows_above: r = rows_above.pop(0) diff --git a/urwid/treetools.py b/urwid/treetools.py index e948dc6..f2b1aad 100644 --- a/urwid/treetools.py +++ b/urwid/treetools.py @@ -20,6 +20,8 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + """ Urwid tree view diff --git a/urwid/util.py b/urwid/util.py index 3569f8c..f57c898 100644 --- a/urwid/util.py +++ b/urwid/util.py @@ -20,8 +20,10 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + from urwid import escape -from urwid.compat import bytes +from urwid.compat import bytes, text_type, text_types import codecs @@ -108,7 +110,7 @@ def apply_target_encoding( s ): """ Return (encoded byte string, character set rle). """ - if _use_dec_special and type(s) == unicode: + if _use_dec_special and type(s) == text_type: # first convert drawing characters try: s = s.translate( escape.DEC_SPECIAL_CHARMAP ) @@ -118,7 +120,7 @@ def apply_target_encoding( s ): escape.ALT_DEC_SPECIAL_CHARS): s = s.replace( c, escape.SO+alt+escape.SI ) - if type(s) == unicode: + if type(s) == text_type: s = s.replace(escape.SI+escape.SO, u"") # remove redundant shifts s = codecs.encode(s, _target_encoding, 'replace') @@ -412,7 +414,7 @@ def _tagmarkup_recurse( tm, attr ): attr, element = tm return _tagmarkup_recurse( element, attr ) - if not isinstance(tm,(basestring, bytes)): + if not isinstance(tm, text_types + (bytes,)): raise TagMarkupException("Invalid markup element: %r" % tm) # text diff --git a/urwid/version.py b/urwid/version.py index e34283f..7b70ec5 100644 --- a/urwid/version.py +++ b/urwid/version.py @@ -1,3 +1,4 @@ +from __future__ import division, print_function VERSION = (1, 3, 1) __version__ = ''.join(['-.'[type(x) == int]+str(x) for x in VERSION])[1:] diff --git a/urwid/vterm.py b/urwid/vterm.py index 0f091ea..0c91ca5 100644 --- a/urwid/vterm.py +++ b/urwid/vterm.py @@ -20,6 +20,8 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + import os import sys import time @@ -43,7 +45,7 @@ from urwid.escape import DEC_SPECIAL_CHARS, ALT_DEC_SPECIAL_CHARS from urwid.canvas import Canvas from urwid.widget import Widget, BOX from urwid.display_common import AttrSpec, RealTerminal, _BASIC_COLORS -from urwid.compat import ord2, chr2, B, bytes, PYTHON3 +from urwid.compat import ord2, chr2, B, bytes, PYTHON3, xrange ESC = chr(27) diff --git a/urwid/web_display.py b/urwid/web_display.py index 44a505c..2b2de46 100755 --- a/urwid/web_display.py +++ b/urwid/web_display.py @@ -19,6 +19,8 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + """ Urwid web application display module """ @@ -659,7 +661,7 @@ class Screen: urwid_id = "%09d%09d"%(random.randrange(10**9), random.randrange(10**9)) self.pipe_name = os.path.join(_prefs.pipe_dir,"urwid"+urwid_id) - os.mkfifo(self.pipe_name+".in",0600) + os.mkfifo(self.pipe_name+".in",0o600) signal.signal(signal.SIGTERM,self._cleanup_pipe) self.input_fd = os.open(self.pipe_name+".in", @@ -743,9 +745,11 @@ class Screen: rows = MAX_ROWS self.screen_size = cols, rows - def draw_screen(self, (cols, rows), r ): + def draw_screen(self, size, r ): """Send a screen update to the client.""" + (cols, rows) = size + if cols != self.last_screen_width: self.last_screen = {} diff --git a/urwid/widget.py b/urwid/widget.py index 7901f9b..97cc4b9 100644 --- a/urwid/widget.py +++ b/urwid/widget.py @@ -19,8 +19,11 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + from operator import attrgetter +from urwid.compat import text_type, with_metaclass from urwid.util import (MetaSuper, decompose_tagmarkup, calc_width, is_wide_char, move_prev_char, move_next_char) from urwid.text_layout import calc_pos, calc_coords, shift_line @@ -203,15 +206,10 @@ def cache_widget_rows(cls): return cached_rows -class Widget(object): +class Widget(with_metaclass(WidgetMeta, object)): """ Widget base class - .. attribute:: __metaclass__ - :annotation: = urwid.WidgetMeta - - See :class:`urwid.WidgetMeta` definition - .. attribute:: _selectable :annotation: = False @@ -443,8 +441,6 @@ class Widget(object): :returns: ``True`` if the position was set successfully anywhere on *row*, ``False`` otherwise """ - __metaclass__ = WidgetMeta - _selectable = False _sizing = frozenset([FLOW, BOX, FIXED]) _command_map = command_map @@ -827,7 +823,7 @@ class Text(Widget): >>> t = Text(('bold', u"stuff"), 'right', 'any') >>> t - >>> print t.text + >>> print(t.text) stuff >>> t.attrib [('bold', 5)] @@ -868,10 +864,10 @@ class Text(Widget): :type markup: text markup >>> t = Text(u"foo") - >>> print t.text + >>> print(t.text) foo >>> t.set_text(u"bar") - >>> print t.text + >>> print(t.text) bar >>> t.text = u"baz" # not supported because text stores text but set_text() takes markup Traceback (most recent call last): @@ -1287,10 +1283,10 @@ class Edit(Text): >>> e = Edit("") >>> e.set_caption("cap1") - >>> print e.caption + >>> print(e.caption) cap1 >>> e.set_caption(('bold', "cap2")) - >>> print e.caption + >>> print(e.caption) cap2 >>> e.attrib [('bold', 4)] @@ -1360,12 +1356,12 @@ class Edit(Text): >>> e = Edit() >>> e.set_edit_text(u"yes") - >>> print e.edit_text + >>> print(e.edit_text) yes >>> e >>> e.edit_text = u"no" # Urwid 0.9.9 or later - >>> print e.edit_text + >>> print(e.edit_text) no """ text = self._normalize_to_caption(text) @@ -1383,9 +1379,9 @@ class Edit(Text): Return the edit text for this widget. >>> e = Edit(u"What? ", u"oh, nothing.") - >>> print e.get_edit_text() + >>> print(e.get_edit_text()) oh, nothing. - >>> print e.edit_text + >>> print(e.edit_text) oh, nothing. """ return self._edit_text @@ -1410,7 +1406,7 @@ class Edit(Text): >>> e.set_edit_pos(2) >>> e.insert_text(u"a") - >>> print e.edit_text + >>> print(e.edit_text) 42a.5 """ text = self._normalize_to_caption(text) @@ -1424,8 +1420,8 @@ class Edit(Text): Return text converted to the same type as self.caption (bytes or unicode) """ - tu = isinstance(text, unicode) - cu = isinstance(self._caption, unicode) + tu = isinstance(text, text_type) + cu = isinstance(self._caption, text_type) if tu == cu: return text if tu: @@ -1469,12 +1465,12 @@ class Edit(Text): >>> e.keypress(size, 'x') >>> e.keypress(size, 'left') >>> e.keypress(size, '1') - >>> print e.edit_text + >>> print(e.edit_text) 1x >>> e.keypress(size, 'backspace') >>> e.keypress(size, 'end') >>> e.keypress(size, '2') - >>> print e.edit_text + >>> print(e.edit_text) x2 >>> e.keypress(size, 'shift f1') 'shift f1' @@ -1483,8 +1479,8 @@ class Edit(Text): p = self.edit_pos if self.valid_char(key): - if (isinstance(key, unicode) and not - isinstance(self._caption, unicode)): + if (isinstance(key, text_type) and not + isinstance(self._caption, text_type)): # screen is sending us unicode input, must be using utf-8 # encoding because that's all we support, so convert it # to bytes to match our caption's type @@ -1718,10 +1714,10 @@ class IntEdit(Edit): >>> e, size = IntEdit(u"", 5002), (10,) >>> e.keypress(size, 'home') >>> e.keypress(size, 'delete') - >>> print e.edit_text + >>> print(e.edit_text) 002 >>> e.keypress(size, 'end') - >>> print e.edit_text + >>> print(e.edit_text) 2 """ (maxcol,) = size @@ -1746,7 +1742,7 @@ class IntEdit(Edit): True """ if self.edit_text: - return long(self.edit_text) + return int(self.edit_text) else: return 0 diff --git a/urwid/wimp.py b/urwid/wimp.py index ea73fb4..62a0819 100755 --- a/urwid/wimp.py +++ b/urwid/wimp.py @@ -19,6 +19,8 @@ # # Urwid web site: http://excess.org/urwid/ +from __future__ import division, print_function + from urwid.widget import (Text, WidgetWrap, delegate_to_widget_mixin, BOX, FLOW) from urwid.canvas import CompositeCanvas @@ -184,12 +186,12 @@ class CheckBox(WidgetWrap): Return label text. >>> cb = CheckBox(u"Seriously") - >>> print cb.get_label() + >>> print(cb.get_label()) Seriously - >>> print cb.label + >>> print(cb.label) Seriously >>> cb.set_label([('bright_attr', u"flashy"), u" normal"]) - >>> print cb.label # only text is returned + >>> print(cb.label) # only text is returned flashy normal """ return self._label.text @@ -507,9 +509,9 @@ class Button(WidgetWrap): Return label text. >>> b = Button(u"Ok") - >>> print b.get_label() + >>> print(b.get_label()) Ok - >>> print b.label + >>> print(b.label) Ok """ return self._label.text -- cgit v1.2.1