summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Dunai <andunai@gmail.com>2018-01-04 13:56:40 +0200
committerGitHub <noreply@github.com>2018-01-04 13:56:40 +0200
commitcf0307c500e1d575fec5fc5a37e4ff4e69972b92 (patch)
treecbc82f80d72cb15589f50c77847dc4c0ddabd072
parent2496a176c00eab88492f1566f2a89c58be4e15d9 (diff)
downloadurwid-cf0307c500e1d575fec5fc5a37e4ff4e69972b92.tar.gz
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.
-rw-r--r--examples/twisted_serve_ssh.py6
-rw-r--r--setup.py3
-rw-r--r--urwid/__init__.py2
-rw-r--r--urwid/canvas.py18
-rw-r--r--urwid/command_map.py2
-rw-r--r--urwid/compat.py26
-rwxr-xr-xurwid/container.py15
-rwxr-xr-xurwid/curses_display.py12
-rwxr-xr-xurwid/decoration.py13
-rwxr-xr-xurwid/display_common.py9
-rw-r--r--urwid/escape.py2
-rwxr-xr-xurwid/font.py38
-rwxr-xr-xurwid/graphics.py39
-rw-r--r--urwid/highlight.css19
-rwxr-xr-xurwid/html_fragment.py16
-rw-r--r--urwid/lcd_display.py5
-rw-r--r--urwid/listbox.py45
-rwxr-xr-xurwid/main_loop.py13
-rwxr-xr-xurwid/monitored_list.py20
-rwxr-xr-xurwid/old_str_util.py11
-rw-r--r--urwid/raw_display.py7
-rw-r--r--urwid/signals.py3
-rwxr-xr-xurwid/split_repr.py8
-rw-r--r--urwid/tests/test_doctests.py1
-rw-r--r--urwid/tests/test_vterm.py2
-rw-r--r--urwid/tests/test_widget.py8
-rw-r--r--urwid/text_layout.py8
-rw-r--r--urwid/treetools.py2
-rw-r--r--urwid/util.py10
-rw-r--r--urwid/version.py1
-rw-r--r--urwid/vterm.py4
-rwxr-xr-xurwid/web_display.py8
-rw-r--r--urwid/widget.py50
-rwxr-xr-xurwid/wimp.py12
34 files changed, 285 insertions, 153 deletions
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):
<AttrMap selectable flow widget <Edit selectable flow widget '' edit_pos=0> 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
<AttrMap flow widget <Text flow widget 'hi'> 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):
<AttrWrap selectable flow widget <Edit selectable flow widget '' edit_pos=0> 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
+ <ProgressBar flow widget>
+ >>> 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
<Text flow widget 'stuff' align='right' wrap='any'>
- >>> 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
<Edit selectable flow widget 'yes' edit_pos=0>
>>> 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):
<Edit selectable flow widget '42.5' edit_pos=4>
>>> 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