[Python-modules-team] Bug#789767: urwid uploaded to DELAYED/15
Gianfranco Costamagna
costamagnagianfranco at yahoo.it
Wed Sep 16 10:03:31 UTC 2015
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
Hi,
since there has been no maintainer response since months, I did
prepare an update (Team Upload, since the package is team maintained)
and pushed on DELAYED/15.
Please review it (I'm attaching the full debdiff and the Debian only
debdiff for your best convenience), and let me know if I should cancel
it or delay any longer.
List of changes:
* Team upload.
* Refactor rules file to use pybuild.
* Remove cdbs to build.
* New upstream release. (Closes: #789767)
* watch file: use pypi debian redirectory
* Bump compat level to 9
* Update standard version to 3.9.6, no changes required.
This refactor also fixed some issues, e.g. wrong permission bits for
the installed files.
cheers,
Gianfranco
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
iQIcBAEBCAAGBQJV+T5yAAoJEPNPCXROn13ZZjIP/1WWTmxQxqpzu6gnnr+T2Ujm
2te/AOw2bKg5D2SqAEVsO4Vrzu9wzrqKvHjnEPSXhiJtqroxhNIQGt53qrDvJ3Ez
T52AfF41QB2i4y7ifc4lY/RUBxxw4ItQ4D17CROhfPk+GltejMLyuHFPsuJzp6mW
Wp2mEavbiPDuxJszDSKGNlQVbpJdxSU1eRWwAXYGlfPtAJKCgxURAxch0PY3j567
2pTU/dVqZWcYwLdR80Y3CTDF5u5Jv1iq830V5KIssIvIhFLw4ZlmQp0JYUoVpSpb
v8KOUGnGQMvwUfnFbIl/w0IYXTbfLx/AHhUKaXQ+3O4UI3iJSFEV5Lh7emLM9ZTH
PLR5u5kns8E/BCvn71eKjoBcbP/XaaJIV5whhfSRvzs78hzYWhdiYHsNHXdHrAj3
k0SbOUYq0uTQuFF4B2bQRrYc8iVKN83oxPElm0F4IbsHyuoQorbNzLqFNGZcM4PT
OyPY7vJQ1ZMey8FXjCZdG6vl1mz2nDbYwQziEGLwvZ1aKbcg4wiyOjFGPs5Xh2VE
b8BN0sCUS/2fbXLHsk4kpQODi03lY7udqcnYVCY2mbZgeUvcgHj6KYZntfFNFGws
21kD3UD9lYdFdtdpcQB9HT8PgsCgmppOlSQjFNGd2Cux7gvSoaYAJs3sOs8BYa00
y0e/dEHMizfmpIGJTiCq
=5PL5
-----END PGP SIGNATURE-----
-------------- next part --------------
diff -Nru urwid-1.2.1/debian/changelog urwid-1.3.0/debian/changelog
--- urwid-1.2.1/debian/changelog 2014-05-18 11:08:47.000000000 +0200
+++ urwid-1.3.0/debian/changelog 2015-09-16 11:57:47.000000000 +0200
@@ -1,3 +1,15 @@
+urwid (1.3.0-1) unstable; urgency=medium
+
+ * Team upload.
+ * Refactor rules file to use pybuild.
+ * Remove cdbs to build.
+ * New upstream release. (Closes: #789767)
+ * watch file: use pypi debian redirectory
+ * Bump compat level to 9
+ * Update standard version to 3.9.6, no changes required.
+
+ -- Gianfranco Costamagna <locutusofborg at debian.org> Tue, 15 Sep 2015 16:04:33 +0200
+
urwid (1.2.1-2) unstable; urgency=medium
* Team upload.
diff -Nru urwid-1.2.1/debian/compat urwid-1.3.0/debian/compat
--- urwid-1.2.1/debian/compat 2014-04-04 18:49:51.000000000 +0200
+++ urwid-1.3.0/debian/compat 2015-09-16 11:57:09.000000000 +0200
@@ -1 +1 @@
-5
+9
diff -Nru urwid-1.2.1/debian/control urwid-1.3.0/debian/control
--- urwid-1.2.1/debian/control 2014-04-04 19:08:58.000000000 +0200
+++ urwid-1.3.0/debian/control 2015-09-16 11:57:09.000000000 +0200
@@ -4,8 +4,7 @@
Maintainer: Debian Python Modules Team <python-modules-team at lists.alioth.debian.org>
Uploaders: Ian Ward <ian at excess.org>
Build-Depends:
- cdbs (>= 0.4.90~),
- debhelper (>= 5.0.37.2),
+ debhelper (>= 9),
python-all-dev (>= 2.6.6-3~),
python-gobject,
python-setuptools (>= 0.6.16),
@@ -13,7 +12,7 @@
python-twisted,
python3-all-dev (>= 3.2),
python3-setuptools
-Standards-Version: 3.9.5
+Standards-Version: 3.9.6
Homepage: http://excess.org/urwid/
Vcs-Svn: svn://anonscm.debian.org/python-modules/packages/urwid/trunk/
Vcs-Browser: http://anonscm.debian.org/viewvc/python-modules/packages/urwid/trunk/
diff -Nru urwid-1.2.1/debian/python3-urwid.install urwid-1.3.0/debian/python3-urwid.install
--- urwid-1.2.1/debian/python3-urwid.install 2014-04-04 19:02:24.000000000 +0200
+++ urwid-1.3.0/debian/python3-urwid.install 1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-debian/tmp/usr/lib/python3*
diff -Nru urwid-1.2.1/debian/python-urwid.install urwid-1.3.0/debian/python-urwid.install
--- urwid-1.2.1/debian/python-urwid.install 2014-04-04 19:02:24.000000000 +0200
+++ urwid-1.3.0/debian/python-urwid.install 1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-debian/tmp/usr/lib/python2*
diff -Nru urwid-1.2.1/debian/rules urwid-1.3.0/debian/rules
--- urwid-1.2.1/debian/rules 2014-05-18 11:07:29.000000000 +0200
+++ urwid-1.3.0/debian/rules 2015-09-16 11:57:09.000000000 +0200
@@ -1,35 +1,10 @@
#!/usr/bin/make -f
-DEB_PYTHON_DISTUTILS_INSTALLDIR_SKEL=/usr/lib/@PYTHONBINARY@/dist-packages/
-DEB_PYTHON_INSTALL_ARGS_ALL=--prefix=/usr --no-compile -O0 --install-layout=deb
+export PYBUILD_NAME=urwid
-include /usr/share/cdbs/1/rules/debhelper.mk
-DEB_INSTALL_CHANGELOGS_ALL=docs/changelog.rst
-include /usr/share/cdbs/1/class/python-distutils.mk
+%:
+ dh $@ --with python2,python3 --buildsystem=pybuild
-build/python-urwid:: build-docs-test-stamp
-build-docs-test-stamp:
-ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
- set -e; for python in $(shell pyversions -r) $(shell py3versions -r); do \
- echo Testing with $$python; \
- $$python setup.py test; \
- done;
-else
- @echo "** tests disabled"
-endif
+override_dh_auto_build:
python setup.py build_sphinx
- touch build-docs-test-stamp
-
-install/python-urwid::
- chmod a+x debian/tmp/usr/lib/python*/dist-packages/urwid/*.py
- chmod a-x debian/tmp/usr/lib/python*/dist-packages/urwid/version.py
-
-install/python3-urwid::
- mv debian/tmp/usr/lib/$(shell py3versions -d) debian/tmp/usr/lib/python3
- -cp debian/tmp/usr/lib/python3.*/dist-packages/urwid/*.so debian/tmp/usr/lib/python3/dist-packages/urwid/
- rm -rf debian/tmp/usr/lib/python3.*
-
-clean::
- rm -rf build build-docs-test-stamp urwid.egg-info
- rm -f urwid/tests/test_vterm.py
- find . -name '*.so' -delete
+ dh_auto_build
diff -Nru urwid-1.2.1/debian/watch urwid-1.3.0/debian/watch
--- urwid-1.2.1/debian/watch 2014-04-04 18:49:51.000000000 +0200
+++ urwid-1.3.0/debian/watch 2015-09-16 11:57:09.000000000 +0200
@@ -1,2 +1,3 @@
version=3
-http://pypi.python.org/packages/source/u/urwid/urwid-(.*).tar.gz
+opts=uversionmangle=s/(rc|a|b|c)/~$1/ \
+https://pypi.debian.net/urwid/urwid-(.+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))
diff -Nru urwid-1.2.1/docs/changelog.rst urwid-1.3.0/docs/changelog.rst
--- urwid-1.2.1/docs/changelog.rst 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/changelog.rst 2014-10-17 20:09:04.000000000 +0200
@@ -2,6 +2,40 @@
Changelog
---------
+Urwid 1.3.0
+===========
+
+2014-10-17
+
+ * New AsyncioEventLoop for Python 3.4, Python 3.x with asyncio
+ package or Python 2 with trollius package (by Alex Munroe,
+ Jonas Wielicki, with earlier work by Kelketek Rritaa)
+
+ * Screen classes now call back to MainLoop using event loop alarms
+ instead of passing timeout values to MainLoop (by Alex Munroe)
+
+ * Add support for bright backgrounds on linux console
+ (by Russell Warren)
+
+ * Allow custom sorting of MonitoredList (by Tony Cebzanov)
+
+ * Fix support for negative indexes with MonitoredFocusList
+ (by Heiko Noordhof)
+
+ * Documentation fixes (by Ismail, Matthew Mosesohn)
+
+Urwid 1.2.2
+===========
+
+2014-10-05
+
+ * Fix for a serious raw_display performance regression
+ (by Anton Khirnov)
+
+ * Fix for high color palette detection (by extempo)
+
+ * Small changes to enable windows support (by Jeanpierre Devin)
+
Urwid 1.2.1
===========
diff -Nru urwid-1.2.1/docs/examples/bigtext.py urwid-1.3.0/docs/examples/bigtext.py
--- urwid-1.2.1/docs/examples/bigtext.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/examples/bigtext.py 2014-10-17 20:09:04.000000000 +0200
@@ -50,7 +50,7 @@
('chars', 'light gray', 'black'),
('exit', 'white', 'dark cyan'),
]
-
+
def create_radio_button(self, g, name, font, fn):
w = urwid.RadioButton(g, name, False, on_state_change=fn)
w.font = font
@@ -61,7 +61,7 @@
w = urwid.Text(" " + name + " (UTF-8 mode required)")
w = urwid.AttrWrap(w, 'button disabled')
return w
-
+
def create_edit(self, label, text, fn):
w = urwid.Edit(label, text)
urwid.connect_signal(w, 'change', fn)
@@ -94,35 +94,35 @@
chosen_font_rb = rb
exit_font = font
self.font_buttons.append( rb )
-
+
# Create BigText
self.bigtext = urwid.BigText("", None)
bt = SwitchingPadding(self.bigtext, 'left', None)
bt = urwid.AttrWrap(bt, 'bigtext')
bt = urwid.Filler(bt, 'bottom', None, 7)
bt = urwid.BoxAdapter(bt, 7)
-
+
# Create chars_avail
cah = urwid.Text("Characters Available:")
self.chars_avail = urwid.Text("", wrap='any')
ca = urwid.AttrWrap(self.chars_avail, 'chars')
-
+
chosen_font_rb.set_state(True) # causes set_font_event call
-
+
# Create Edit widget
edit = self.create_edit("", "Urwid "+urwid.__version__,
self.edit_change_event)
-
+
# ListBox
chars = urwid.Pile([cah, ca])
fonts = urwid.Pile([urwid.Text("Fonts:")] + self.font_buttons,
focus_item=1)
- col = urwid.Columns([('fixed',16,chars), fonts], 3,
+ col = urwid.Columns([('fixed',16,chars), fonts], 3,
focus_column=1)
bt = urwid.Pile([bt, edit], focus_item=1)
l = [bt, urwid.Divider(), col]
w = urwid.ListBox(urwid.SimpleListWalker(l))
-
+
# Frame
w = urwid.AttrWrap(w, 'body')
hdr = urwid.Text("Urwid BigText example program - F8 exits.")
@@ -137,10 +137,10 @@
def main(self):
self.view, self.exit_view = self.setup_view()
- self.loop = urwid.MainLoop(self.view, self.palette,
+ self.loop = urwid.MainLoop(self.view, self.palette,
unhandled_input=self.unhandled_input)
self.loop.run()
-
+
def unhandled_input(self, key):
if key == 'f8':
self.loop.widget = self.exit_view
@@ -152,10 +152,10 @@
if key in ('n', 'N'):
self.loop.widget = self.view
return True
-
+
def main():
BigTextDisplay().main()
-
+
if '__main__'==__name__:
main()
diff -Nru urwid-1.2.1/docs/examples/graph.py urwid-1.3.0/docs/examples/graph.py
--- urwid-1.2.1/docs/examples/graph.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/examples/graph.py 2014-10-17 20:09:04.000000000 +0200
@@ -20,7 +20,7 @@
# Urwid web site: http://excess.org/urwid/
"""
-Urwid example demonstrating use of the BarGraph widget and creating a
+Urwid example demonstrating use of the BarGraph widget and creating a
floating-window appearance. Also shows use of alarms to create timed
animation.
"""
@@ -33,12 +33,12 @@
UPDATE_INTERVAL = 0.2
def sin100( x ):
- """
+ """
A sin function that returns values between 0 and 100 and repeats
after x == 100.
"""
return 50 + 50 * math.sin( x * math.pi / 50 )
-
+
class GraphModel:
"""
A class responsible for storing the data that will be displayed
@@ -46,14 +46,14 @@
"""
data_max_value = 100
-
+
def __init__(self):
data = [ ('Saw', range(0,100,2)*2),
('Square', [0]*30 + [100]*30),
('Sine 1', [sin100(x) for x in range(100)] ),
- ('Sine 2', [(sin100(x) + sin100(x*2))/2
+ ('Sine 2', [(sin100(x) + sin100(x*2))/2
for x in range(100)] ),
- ('Sine 3', [(sin100(x) + sin100(x*3))/2
+ ('Sine 3', [(sin100(x) + sin100(x*3))/2
for x in range(100)] ),
]
self.modes = []
@@ -61,13 +61,13 @@
for m, d in data:
self.modes.append(m)
self.data[m] = d
-
+
def get_modes(self):
return self.modes
-
+
def set_mode(self, m):
self.current_mode = m
-
+
def get_data(self, offset, r):
"""
Return the data in [offset:offset+r], the maximum value
@@ -108,11 +108,11 @@
('pg complete', 'white', 'dark magenta'),
('pg smooth', 'dark magenta','black')
]
-
+
graph_samples_per_bar = 10
graph_num_bars = 5
graph_offset_per_second = 5
-
+
def __init__(self, controller):
self.controller = controller
self.started = True
@@ -146,7 +146,7 @@
else:
l.append([value,0])
self.graph.set_data(l,max_value)
-
+
# also update progress
if (o//repeat)&1:
# show 100% for first half, 0 for second half
@@ -171,8 +171,8 @@
self.started = True
self.start_time = time.time()
self.controller.animate_graph()
-
-
+
+
def on_reset_button(self, w):
self.offset = 0
self.start_time = time.time()
@@ -199,13 +199,13 @@
self.animate_progress = self.progress_bar( state )
self.animate_progress_wrap._w = self.animate_progress
self.update_graph( True )
-
+
def main_shadow(self, w):
"""Wrap a shadow and background around widget w."""
bg = urwid.AttrWrap(urwid.SolidFill(u"\u2592"), 'screen edge')
shadow = urwid.AttrWrap(urwid.SolidFill(u" "), 'main shadow')
-
+
bg = urwid.Overlay( shadow, bg,
('fixed left', 3), ('fixed right', 1),
('fixed top', 2), ('fixed bottom', 1))
@@ -213,7 +213,7 @@
('fixed left', 2), ('fixed right', 3),
('fixed top', 1), ('fixed bottom', 2))
return w
-
+
def bar_graph(self, smooth=False):
satt = None
if smooth:
@@ -233,7 +233,7 @@
def progress_bar(self, smooth=False):
if smooth:
- return urwid.ProgressBar('pg normal', 'pg complete',
+ return urwid.ProgressBar('pg normal', 'pg complete',
0, 1, 'pg smooth')
else:
return urwid.ProgressBar('pg normal', 'pg complete',
@@ -255,11 +255,11 @@
self.on_animate_button( self.animate_button )
self.offset = 0
self.animate_progress = self.progress_bar()
- animate_controls = urwid.GridFlow( [
+ animate_controls = urwid.GridFlow( [
self.animate_button,
self.button("Reset", self.on_reset_button),
], 9, 2, 0, 'center')
-
+
if urwid.get_encoding_mode() == "utf8":
unicode_checkbox = urwid.CheckBox(
"Enable Unicode Graphics",
@@ -267,10 +267,10 @@
else:
unicode_checkbox = urwid.Text(
"UTF-8 encoding not detected")
-
+
self.animate_progress_wrap = urwid.WidgetWrap(
self.animate_progress)
-
+
l = [ urwid.Text("Mode",align="center"),
] + self.mode_buttons + [
urwid.Divider(),
@@ -285,7 +285,7 @@
w = urwid.ListBox(urwid.SimpleListWalker(l))
return w
- def main_window(self):
+ def main_window(self):
self.graph = self.bar_graph()
self.graph_wrap = urwid.WidgetWrap( self.graph )
vline = urwid.AttrWrap( urwid.SolidFill(u'\u2502'), 'line')
@@ -299,7 +299,7 @@
w = urwid.AttrWrap(w,'line')
w = self.main_shadow(w)
return w
-
+
class GraphController:
"""
@@ -320,17 +320,17 @@
def get_modes(self):
"""Allow our view access to the list of modes."""
return self.model.get_modes()
-
+
def set_mode(self, m):
"""Allow our view to set the mode."""
rval = self.model.set_mode( m )
self.view.update_graph(True)
return rval
-
+
def get_data(self, offset, range):
"""Provide data to our view for the graph."""
return self.model.get_data( offset, range )
-
+
def main(self):
self.loop = urwid.MainLoop(self.view, self.view.palette)
@@ -347,10 +347,10 @@
if self.animate_alarm:
self.loop.remove_alarm(self.animate_alarm)
self.animate_alarm = None
-
+
def main():
GraphController().main()
-
+
if '__main__'==__name__:
main()
diff -Nru urwid-1.2.1/docs/examples/palette_test.py urwid-1.3.0/docs/examples/palette_test.py
--- urwid-1.2.1/docs/examples/palette_test.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/examples/palette_test.py 2014-10-17 20:09:04.000000000 +0200
@@ -34,10 +34,10 @@
brown__ dark_red_ dark_magenta_ dark_blue_ dark_cyan_ dark_green_
yellow_ light_red light_magenta light_blue light_cyan light_green
- #00f#06f#08f#0af#0df#0ff black_______ dark_gray___
+ #00f#06f#08f#0af#0df#0ff black_______ dark_gray___
#60f#00d#06d#08d#0ad#0dd#0fd light_gray__ white_______
- #80f#60d#00a#06a#08a#0aa#0da#0fa
- #a0f#80d#60a#008#068#088#0a8#0d8#0f8
+ #80f#60d#00a#06a#08a#0aa#0da#0fa
+ #a0f#80d#60a#008#068#088#0a8#0d8#0f8
#d0f#a0d#80d#608#006#066#086#0a6#0d6#0f6
#f0f#d0d#a0a#808#606#000#060#080#0a0#0d0#0f0#0f6#0f8#0fa#0fd#0ff
#f0d#d0a#a08#806#600#660#680#6a0#6d0#6f0#6f6#6f8#6fa#6fd#6ff#0df
@@ -50,29 +50,29 @@
#86d#66a#68a#6aa#6da #f80#f86#f88#f8a#f8d#f8f#d6f#a0f
#a6d#86a#668#688#6a8#6d8 #f60#f66#f68#f6a#f6d#f6f#d0f
#d6d#a6a#868#666#686#6a6#6d6#6d8#6da#6dd #f00#f06#f08#f0a#f0d#f0f
- #d6a#a68#866#886#8a6#8d6#8d8#8da#8dd#6ad
- #d68#a66#a86#aa6#ad6#ad8#ada#add#8ad#68d
- #d66#d86#da6#dd6#dd8#dda#ddd#aad#88d#66d g78_g82_g85_g89_g93_g100
+ #d6a#a68#866#886#8a6#8d6#8d8#8da#8dd#6ad
+ #d68#a66#a86#aa6#ad6#ad8#ada#add#8ad#68d
+ #d66#d86#da6#dd6#dd8#dda#ddd#aad#88d#66d g78_g82_g85_g89_g93_g100
#da6#da8#daa#dad#a8d#86d g52_g58_g62_g66_g70_g74_
#88a#8aa #d86#d88#d8a#d8d#a6d g27_g31_g35_g38_g42_g46_g50_
#a8a#888#8a8#8aa #d66#d68#d6a#d6d g0__g3__g7__g11_g15_g19_g23_
- #a88#aa8#aaa#88a
+ #a88#aa8#aaa#88a
#a88#a8a
-"""
+"""
CHART_88 = """
brown__ dark_red_ dark_magenta_ dark_blue_ dark_cyan_ dark_green_
yellow_ light_red light_magenta light_blue light_cyan light_green
- #00f#08f#0cf#0ff black_______ dark_gray___
- #80f#00c#08c#0cc#0fc light_gray__ white_______
+ #00f#08f#0cf#0ff black_______ dark_gray___
+ #80f#00c#08c#0cc#0fc light_gray__ white_______
#c0f#80c#008#088#0c8#0f8
-#f0f#c0c#808#000#080#0c0#0f0#0f8#0fc#0ff #88c#8cc
- #f0c#c08#800#880#8c0#8f0#8f8#8fc#8ff#0cf #c8c#888#8c8#8cc
+#f0f#c0c#808#000#080#0c0#0f0#0f8#0fc#0ff #88c#8cc
+ #f0c#c08#800#880#8c0#8f0#8f8#8fc#8ff#0cf #c8c#888#8c8#8cc
#f08#c00#c80#cc0#cf0#cf8#cfc#cff#8cf#08f #c88#cc8#ccc#88c
- #f00#f80#fc0#ff0#ff8#ffc#fff#ccf#88f#00f #c88#c8c
- #fc0#fc8#fcc#fcf#c8f#80f
- #f80#f88#f8c#f8f#c0f g62_g74_g82_g89_g100
+ #f00#f80#fc0#ff0#ff8#ffc#fff#ccf#88f#00f #c88#c8c
+ #fc0#fc8#fcc#fcf#c8f#80f
+ #f80#f88#f8c#f8f#c0f g62_g74_g82_g89_g100
#f00#f08#f0c#f0f g0__g19_g35_g46_g52
"""
@@ -80,7 +80,7 @@
brown__ dark_red_ dark_magenta_ dark_blue_ dark_cyan_ dark_green_
yellow_ light_red light_magenta light_blue light_cyan light_green
-black_______ dark_gray___ light_gray__ white_______
+black_______ dark_gray___ light_gray__ white_______
"""
ATTR_RE = re.compile("(?P<whitespace>[ \n]*)(?P<entry>[^ \n]+)")
@@ -115,7 +115,7 @@
attr, text = attrtext
out.append((attr, text.ljust(elen)))
return out
-
+
def foreground_chart(chart, background, colors):
"""
Create text markup for a foreground colour chart
@@ -199,7 +199,7 @@
if state:
is_foreground_chart = chart_radio_buttons[0].state
set_mode(colors, is_foreground_chart)
-
+
def mode_rb(text, colors, state=False):
# mode radio buttons
rb = urwid.RadioButton(mode_radio_buttons, text, state)
@@ -209,10 +209,10 @@
def on_chart_change(rb, state):
# handle foreground check box state change
set_mode(screen.colors, state)
-
+
def click_exit(button):
raise urwid.ExitMainLoop()
-
+
lb.extend([
urwid.AttrMap(urwid.Text("Urwid Palette Test"), 'header'),
urwid.AttrMap(urwid.Columns([
@@ -238,7 +238,7 @@
])
set_mode(16, True) # displays the chart
-
+
def unhandled_input(key):
if key in ('Q','q','esc'):
raise urwid.ExitMainLoop()
diff -Nru urwid-1.2.1/docs/examples/real_browse.py urwid-1.3.0/docs/examples/real_browse.py
--- urwid-1.2.1/docs/examples/real_browse.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/examples/real_browse.py 2014-10-17 20:09:04.000000000 +0200
@@ -93,7 +93,7 @@
def get_display_text(self):
return self.get_node().get_key()
-
+
class EmptyWidget(urwid.TreeWidget):
@@ -164,7 +164,7 @@
else:
depth = path.count(dir_sep())
key = os.path.basename(path)
- urwid.ParentNode.__init__(self, path, key=key, parent=parent,
+ urwid.ParentNode.__init__(self, path, key=key, parent=parent,
depth=depth)
def load_parent(self):
@@ -186,7 +186,7 @@
files.append(a)
except OSError, e:
depth = self.get_depth() + 1
- self._children[None] = ErrorNode(self, parent=self, key=None,
+ self._children[None] = ErrorNode(self, parent=self, key=None,
depth=depth)
return [None]
@@ -199,7 +199,7 @@
keys = dirs + files
if len(keys) == 0:
depth=self.get_depth() + 1
- self._children[None] = EmptyNode(self, parent=self, key=None,
+ self._children[None] = EmptyNode(self, parent=self, key=None,
depth=depth)
keys = [None]
return keys
@@ -226,7 +226,7 @@
('body', 'black', 'light gray'),
('flagged', 'black', 'dark green', ('bold','underline')),
('focus', 'light gray', 'dark blue', 'standout'),
- ('flagged focus', 'yellow', 'dark cyan',
+ ('flagged focus', 'yellow', 'dark cyan',
('bold','standout','underline')),
('head', 'yellow', 'black', 'standout'),
('foot', 'light gray', 'black'),
@@ -236,7 +236,7 @@
('flag', 'dark gray', 'light gray'),
('error', 'dark red', 'light gray'),
]
-
+
footer_text = [
('title', "Directory Browser"), " ",
('key', "UP"), ",", ('key', "DOWN"), ",",
@@ -246,12 +246,12 @@
('key', "+"), ",",
('key', "-"), " ",
('key', "LEFT"), " ",
- ('key', "HOME"), " ",
+ ('key', "HOME"), " ",
('key', "END"), " ",
('key', "Q"),
]
-
-
+
+
def __init__(self):
cwd = os.getcwd()
store_initial_cwd(cwd)
@@ -261,17 +261,17 @@
self.footer = urwid.AttrWrap(urwid.Text(self.footer_text),
'foot')
self.view = urwid.Frame(
- urwid.AttrWrap(self.listbox, 'body'),
- header=urwid.AttrWrap(self.header, 'head'),
+ urwid.AttrWrap(self.listbox, 'body'),
+ header=urwid.AttrWrap(self.header, 'head'),
footer=self.footer)
def main(self):
"""Run the program."""
-
+
self.loop = urwid.MainLoop(self.view, self.palette,
unhandled_input=self.unhandled_input)
self.loop.run()
-
+
# on exit, write the flagged filenames to the console
names = [escape_filename_sh(x) for x in get_flagged_names()]
print " ".join(names)
@@ -299,13 +299,13 @@
def get_flagged_names():
"""Return a list of all filenames marked as flagged."""
-
+
l = []
for w in _widget_cache.values():
if w.flagged:
l.append(w.get_node().get_value())
return l
-
+
######
@@ -314,7 +314,7 @@
def store_initial_cwd(name):
"""Store the initial current working directory path components."""
-
+
global _initial_cwd
_initial_cwd = name.split(dir_sep())
@@ -323,14 +323,14 @@
if name is '/':
return True
-
+
l = name.split(dir_sep())
if len(l) > len(_initial_cwd):
return False
-
+
if l != _initial_cwd[:len(l)]:
return False
-
+
return True
@@ -338,11 +338,11 @@
"""Return a hopefully safe shell-escaped version of a filename."""
# check whether we have unprintable characters
- for ch in name:
- if ord(ch) < 32:
+ for ch in name:
+ if ord(ch) < 32:
# found one so use the ansi-c escaping
return escape_filename_sh_ansic(name)
-
+
# all printable characters, so return a double-quoted version
name.replace('\\','\\\\')
name.replace('"','\\"')
@@ -353,7 +353,7 @@
def escape_filename_sh_ansic(name):
"""Return an ansi-c shell-escaped version of a filename."""
-
+
out =[]
# gather the escaped characters into a list
for ch in name:
@@ -363,7 +363,7 @@
out.append('\\\\')
else:
out.append(ch)
-
+
# slap them back together in an ansi-c quote $'...'
return "$'" + "".join(out) + "'"
@@ -383,6 +383,6 @@
return getattr(os.path,'sep','/')
-if __name__=="__main__":
+if __name__=="__main__":
main()
-
+
diff -Nru urwid-1.2.1/docs/examples/real_edit.py urwid-1.3.0/docs/examples/real_edit.py
--- urwid-1.2.1/docs/examples/real_edit.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/examples/real_edit.py 2014-10-17 20:09:04.000000000 +0200
@@ -37,30 +37,30 @@
class LineWalker(urwid.ListWalker):
"""ListWalker-compatible class for lazily reading file contents."""
-
+
def __init__(self, name):
self.file = open(name)
self.lines = []
self.focus = 0
-
- def get_focus(self):
+
+ def get_focus(self):
return self._get_at_pos(self.focus)
-
+
def set_focus(self, focus):
self.focus = focus
self._modified()
-
+
def get_next(self, start_from):
return self._get_at_pos(start_from + 1)
-
+
def get_prev(self, start_from):
return self._get_at_pos(start_from - 1)
def read_next_line(self):
"""Read another line from the file."""
-
+
next_line = self.file.readline()
-
+
if not next_line or next_line[-1:] != '\n':
# no newline on last line of file
self.file = None
@@ -69,22 +69,22 @@
next_line = next_line[:-1]
expanded = next_line.expandtabs()
-
+
edit = urwid.Edit("", expanded, allow_tab=True)
edit.set_edit_pos(0)
edit.original_text = next_line
self.lines.append(edit)
return next_line
-
-
+
+
def _get_at_pos(self, pos):
"""Return a widget for the line number passed."""
-
+
if pos < 0:
# line 0 is the start of the file, no more above
return None, None
-
+
if len(self.lines) > pos:
# we have that line so return it
return self.lines[pos], pos
@@ -96,12 +96,12 @@
assert pos == len(self.lines), "out of order request?"
self.read_next_line()
-
+
return self.lines[-1], pos
-
+
def split_focus(self):
"""Divide the focus edit widget at the cursor location."""
-
+
focus = self.lines[self.focus]
pos = focus.edit_pos
edit = urwid.Edit("",focus.edit_text[pos:], allow_tab=True)
@@ -117,7 +117,7 @@
if above is None:
# already at the top
return
-
+
focus = self.lines[self.focus]
above.set_edit_pos(len(above.edit_text))
above.set_edit_text(above.edit_text + focus.edit_text)
@@ -131,7 +131,7 @@
if below is None:
# already at bottom
return
-
+
focus = self.lines[self.focus]
focus.set_edit_text(focus.edit_text + below.edit_text)
del self.lines[self.focus+1]
@@ -143,16 +143,16 @@
('foot','dark cyan', 'dark blue', 'bold'),
('key','light cyan', 'dark blue', 'underline'),
]
-
+
footer_text = ('foot', [
"Text Editor ",
('key', "F5"), " save ",
('key', "F8"), " quit",
])
-
+
def __init__(self, name):
self.save_name = name
- self.walker = LineWalker(name)
+ self.walker = LineWalker(name)
self.listbox = urwid.ListBox(self.walker)
self.footer = urwid.AttrWrap(urwid.Text(self.footer_text),
"foot")
@@ -163,7 +163,7 @@
self.loop = urwid.MainLoop(self.view, self.palette,
unhandled_input=self.unhandled_keypress)
self.loop.run()
-
+
def unhandled_keypress(self, k):
"""Last resort for keypresses."""
@@ -197,11 +197,11 @@
else:
return
return True
-
+
def save_file(self):
"""Write the file out to disk."""
-
+
l = []
walk = self.walker
for edit in walk.lines:
@@ -210,14 +210,14 @@
l.append(edit.original_text)
else:
l.append(re_tab(edit.edit_text))
-
+
# then the rest
while walk.file is not None:
l.append(walk.read_next_line())
-
+
# write back to disk
outfile = open(self.save_name, "w")
-
+
prefix = ""
for line in l:
outfile.write(prefix + line)
@@ -249,7 +249,7 @@
sys.stderr.write(__doc__)
return
EditDisplay(name).main()
-
-if __name__=="__main__":
+
+if __name__=="__main__":
main()
diff -Nru urwid-1.2.1/docs/manual/canvascache.rst urwid-1.3.0/docs/manual/canvascache.rst
--- urwid-1.2.1/docs/manual/canvascache.rst 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/manual/canvascache.rst 2014-10-17 20:09:04.000000000 +0200
@@ -12,7 +12,7 @@
rendered for each update.
The :class:`Widget` base class uses some metaclass magic to
-capture the canvas objects returned :meth:`Widget.render` is called and return
+capture the canvas objects returned when :meth:`Widget.render` is called and return
them the next time :meth:`Widget.render` is called again with the same parameters. The
:meth:`Widget._invalidate` method is provided as a way to remove cached widgets so
that changes to the widget are visible the next time the screen is redrawn.
@@ -26,7 +26,7 @@
When container and decoration widgets are rendered, they collect the canvases
returned by their children and arrange them into a composite canvas. Composite
-canvases may are nested to form a tree with the topmost widget's :meth:`Widget.render`
+canvases are nested to form a tree with the topmost widget's :meth:`Widget.render`
method returning the root of the tree. That canvas is sent to the display
module to be rendered on the screen.
diff -Nru urwid-1.2.1/docs/manual/mainloop.rst urwid-1.3.0/docs/manual/mainloop.rst
--- urwid-1.2.1/docs/manual/mainloop.rst 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/manual/mainloop.rst 2014-10-17 20:09:04.000000000 +0200
@@ -59,7 +59,7 @@
Urwid's event loop classes handle waiting for things for the
:class:`MainLoop`. The different event loops allow you to
-integrate with Twisted_, Glib_, Tornado_ libraries,
+integrate with Twisted_, Glib_, Tornado_, Asyncio_ libraries,
or use a simple ``select``-based
loop. Event loop classes abstract the particulars of waiting for input and
calling functions as a result of timeouts.
@@ -76,6 +76,7 @@
.. _Twisted: http://twistedmatrix.com/trac/
.. _Glib: http://developer.gnome.org/glib/stable/
.. _Tornado: http://www.tornadoweb.org/
+.. _Asyncio: https://docs.python.org/3/library/asyncio.html
``SelectEventLoop``
-------------------
@@ -132,9 +133,27 @@
::
from tornado.ioloop import IOLoop
- evl = urwid.TornadoEventLoop(IOLoop()
+ evl = urwid.TornadoEventLoop(IOLoop())
loop = urwid.MainLoop(widget, event_loop=evl)
.. seealso::
- :class`TornadoEventLoop reference <TornadoEventLoop>`
+ :class:`TornadoEventLoop reference <TornadoEventLoop>`
+
+``AsyncioEventLoop``
+--------------------
+
+This event loop integrates with the asyncio module in Python 3.4,
+the asyncio package available for Python 3.3 or the trollius
+package available for Python 2.
+
+::
+
+ import asyncio
+ evl = urwid.AsyncioEventLoop(loop=asyncio.get_event_loop())
+ loop = urwid.MainLoop(widget, event_loop=evl)
+
+.. seealso::
+
+ :class:`AsyncioEventLoop reference <AsyncioEventLoop>`
+
diff -Nru urwid-1.2.1/docs/manual/widgets.rst urwid-1.3.0/docs/manual/widgets.rst
--- urwid-1.2.1/docs/manual/widgets.rst 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/manual/widgets.rst 2014-10-17 20:09:04.000000000 +0200
@@ -29,7 +29,7 @@
7. *(a)* possibly modifies the canvas from *(b)* and returns it
Widgets *(a)*, *(b)* and *(e)* are called container widgets because they
-contain other widgets. Container widgets choose the size and position their
+contain other widgets. Container widgets choose the size and position of their
contained widgets.
Container widgets must also keep track of which one of their contained widgets
@@ -315,7 +315,7 @@
The Overlay widget always treats the top widget as the one in focus. All
keyboard input will be passed to the top widget.
-If you want to use a flow flow widget for the top widget, first wrap the flow
+If you want to use a flow widget for the top widget, first wrap the flow
widget with a :class:`Filler` widget.
diff -Nru urwid-1.2.1/docs/reference/main_loop.rst urwid-1.3.0/docs/reference/main_loop.rst
--- urwid-1.2.1/docs/reference/main_loop.rst 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/reference/main_loop.rst 2014-10-17 20:09:04.000000000 +0200
@@ -28,3 +28,7 @@
.. autoclass:: TornadoEventLoop
+AsyncioEventLoop
+----------------
+
+.. autoclass:: AsyncioEventLoop
diff -Nru urwid-1.2.1/docs/tools/templates/indexcontent.html urwid-1.3.0/docs/tools/templates/indexcontent.html
--- urwid-1.2.1/docs/tools/templates/indexcontent.html 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/docs/tools/templates/indexcontent.html 2014-10-17 20:09:04.000000000 +0200
@@ -42,6 +42,7 @@
<li>python-gi for GlibEventLoop (optional)</li>
<li>Twisted for TwistedEventLoop (optional)</li>
<li>Tornado for TornadoEventLoop (optional)</li>
+<li>asyncio or trollius for AsyncioEventLoop (optional)</li>
<li>Apache for web_display module (optional)</li>
<li>ncurses for curses_display module (optional)</li>
</ul>
@@ -51,6 +52,7 @@
<h3>Similar projects</h3>
<ul>
<li><a href="http://www.npcole.com/npyscreen/">npyscreen</a></li>
+<li><a href="https://github.com/thomasballinger/curtsies">curtsies</a></li>
</ul>
</div>
</div>
diff -Nru urwid-1.2.1/examples/asyncio_socket_server.py urwid-1.3.0/examples/asyncio_socket_server.py
--- urwid-1.2.1/examples/asyncio_socket_server.py 1970-01-01 01:00:00.000000000 +0100
+++ urwid-1.3.0/examples/asyncio_socket_server.py 2014-10-17 20:09:04.000000000 +0200
@@ -0,0 +1,186 @@
+"""Demo of using urwid with Python 3.4's asyncio.
+
+This code works on older Python 3.x if you install `asyncio` from PyPI, and
+even Python 2 if you install `trollius`!
+"""
+from __future__ import print_function
+
+import asyncio
+from datetime import datetime
+import sys
+import weakref
+
+import urwid
+from urwid.raw_display import Screen
+
+
+loop = asyncio.get_event_loop()
+
+
+# -----------------------------------------------------------------------------
+# General-purpose setup code
+
+def build_widgets():
+ input1 = urwid.Edit('What is your name? ')
+ input2 = urwid.Edit('What is your quest? ')
+ input3 = urwid.Edit('What is the capital of Assyria? ')
+ inputs = [input1, input2, input3]
+
+ def update_clock(widget_ref):
+ widget = widget_ref()
+ if not widget:
+ # widget is dead; the main loop must've been destroyed
+ return
+
+ widget.set_text(datetime.now().isoformat())
+
+ # Schedule us to update the clock again in one second
+ loop.call_later(1, update_clock, widget_ref)
+
+ clock = urwid.Text('')
+ update_clock(weakref.ref(clock))
+
+ return urwid.Filler(urwid.Pile([clock] + inputs), 'top')
+
+
+def unhandled(key):
+ if key == 'ctrl c':
+ raise urwid.ExitMainLoop
+
+
+# -----------------------------------------------------------------------------
+# Demo 1
+
+def demo1():
+ """Plain old urwid app. Just happens to be run atop asyncio as the event
+ loop.
+
+ Note that the clock is updated using the asyncio loop directly, not via any
+ of urwid's facilities.
+ """
+ main_widget = build_widgets()
+
+ urwid_loop = urwid.MainLoop(
+ main_widget,
+ event_loop=urwid.AsyncioEventLoop(loop=loop),
+ unhandled_input=unhandled,
+ )
+ urwid_loop.run()
+
+
+# -----------------------------------------------------------------------------
+# Demo 2
+
+class AsyncScreen(Screen):
+ """An urwid screen that speaks to an asyncio stream, rather than polling
+ file descriptors.
+ """
+ def __init__(self, reader, writer):
+ self.reader = reader
+ self.writer = writer
+
+ Screen.__init__(self, None, None)
+
+ _pending_task = None
+
+ def write(self, data):
+ self.writer.write(data)
+
+ def flush(self):
+ pass
+
+ def hook_event_loop(self, event_loop, callback):
+ # Wait on the reader's read coro, and when there's data to read, call
+ # the callback and then wait again
+ def pump_reader(fut=None):
+ if fut is None:
+ # First call, do nothing
+ pass
+ elif fut.cancelled():
+ # This is in response to an earlier .read() call, so don't
+ # schedule another one!
+ return
+ elif fut.exception():
+ pass
+ else:
+ try:
+ self.parse_input(
+ event_loop, callback, bytearray(fut.result()))
+ except urwid.ExitMainLoop:
+ # This will immediately close the transport and thus the
+ # connection, which in turn calls connection_lost, which
+ # stops the screen and the loop
+ self.writer.abort()
+
+ # asyncio.async() schedules a coroutine without using `yield from`,
+ # which would make this code not work on Python 2
+ self._pending_task = asyncio.async(
+ self.reader.read(1024), loop=event_loop._loop)
+ self._pending_task.add_done_callback(pump_reader)
+
+ pump_reader()
+
+ def unhook_event_loop(self, event_loop):
+ if self._pending_task:
+ self._pending_task.cancel()
+ del self._pending_task
+
+
+class UrwidProtocol(asyncio.Protocol):
+ def connection_made(self, transport):
+ print("Got a client!")
+ self.transport = transport
+
+ # StreamReader is super convenient here; it has a regular method on our
+ # end (feed_data), and a coroutine on the other end that will
+ # faux-block until there's data to be read. We could also just call a
+ # method directly on the screen, but this keeps the screen somewhat
+ # separate from the protocol.
+ self.reader = asyncio.StreamReader(loop=loop)
+ screen = AsyncScreen(self.reader, transport)
+
+ main_widget = build_widgets()
+ self.urwid_loop = urwid.MainLoop(
+ main_widget,
+ event_loop=urwid.AsyncioEventLoop(loop=loop),
+ screen=screen,
+ unhandled_input=unhandled,
+ )
+
+ self.urwid_loop.start()
+
+ def data_received(self, data):
+ self.reader.feed_data(data)
+
+ def connection_lost(self, exc):
+ print("Lost a client...")
+ self.reader.feed_eof()
+ self.urwid_loop.stop()
+
+
+def demo2():
+ """Urwid app served over the network to multiple clients at once, using an
+ asyncio Protocol.
+ """
+ coro = loop.create_server(UrwidProtocol, port=12345)
+ loop.run_until_complete(coro)
+ print("OK, good to go! Try this in another terminal (or two):")
+ print()
+ print(" socat TCP:127.0.0.1:12345 STDIN,raw")
+ print()
+ loop.run_forever()
+
+
+if __name__ == '__main__':
+ if len(sys.argv) == 2:
+ which = sys.argv[1]
+ else:
+ which = None
+
+ if which == '1':
+ demo1()
+ elif which == '2':
+ demo2()
+ else:
+ print("Please run me with an argument of either 1 or 2.")
+ sys.exit(1)
diff -Nru urwid-1.2.1/examples/bigtext.py urwid-1.3.0/examples/bigtext.py
--- urwid-1.2.1/examples/bigtext.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/bigtext.py 2014-10-17 20:09:04.000000000 +0200
@@ -50,7 +50,7 @@
('chars', 'light gray', 'black'),
('exit', 'white', 'dark cyan'),
]
-
+
def create_radio_button(self, g, name, font, fn):
w = urwid.RadioButton(g, name, False, on_state_change=fn)
w.font = font
@@ -61,7 +61,7 @@
w = urwid.Text(" " + name + " (UTF-8 mode required)")
w = urwid.AttrWrap(w, 'button disabled')
return w
-
+
def create_edit(self, label, text, fn):
w = urwid.Edit(label, text)
urwid.connect_signal(w, 'change', fn)
@@ -94,35 +94,35 @@
chosen_font_rb = rb
exit_font = font
self.font_buttons.append( rb )
-
+
# Create BigText
self.bigtext = urwid.BigText("", None)
bt = SwitchingPadding(self.bigtext, 'left', None)
bt = urwid.AttrWrap(bt, 'bigtext')
bt = urwid.Filler(bt, 'bottom', None, 7)
bt = urwid.BoxAdapter(bt, 7)
-
+
# Create chars_avail
cah = urwid.Text("Characters Available:")
self.chars_avail = urwid.Text("", wrap='any')
ca = urwid.AttrWrap(self.chars_avail, 'chars')
-
+
chosen_font_rb.set_state(True) # causes set_font_event call
-
+
# Create Edit widget
edit = self.create_edit("", "Urwid "+urwid.__version__,
self.edit_change_event)
-
+
# ListBox
chars = urwid.Pile([cah, ca])
fonts = urwid.Pile([urwid.Text("Fonts:")] + self.font_buttons,
focus_item=1)
- col = urwid.Columns([('fixed',16,chars), fonts], 3,
+ col = urwid.Columns([('fixed',16,chars), fonts], 3,
focus_column=1)
bt = urwid.Pile([bt, edit], focus_item=1)
l = [bt, urwid.Divider(), col]
w = urwid.ListBox(urwid.SimpleListWalker(l))
-
+
# Frame
w = urwid.AttrWrap(w, 'body')
hdr = urwid.Text("Urwid BigText example program - F8 exits.")
@@ -137,10 +137,10 @@
def main(self):
self.view, self.exit_view = self.setup_view()
- self.loop = urwid.MainLoop(self.view, self.palette,
+ self.loop = urwid.MainLoop(self.view, self.palette,
unhandled_input=self.unhandled_input)
self.loop.run()
-
+
def unhandled_input(self, key):
if key == 'f8':
self.loop.widget = self.exit_view
@@ -152,10 +152,10 @@
if key in ('n', 'N'):
self.loop.widget = self.view
return True
-
+
def main():
BigTextDisplay().main()
-
+
if '__main__'==__name__:
main()
diff -Nru urwid-1.2.1/examples/browse.py urwid-1.3.0/examples/browse.py
--- urwid-1.2.1/examples/browse.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/browse.py 2014-10-17 20:09:04.000000000 +0200
@@ -93,7 +93,7 @@
def get_display_text(self):
return self.get_node().get_key()
-
+
class EmptyWidget(urwid.TreeWidget):
@@ -164,7 +164,7 @@
else:
depth = path.count(dir_sep())
key = os.path.basename(path)
- urwid.ParentNode.__init__(self, path, key=key, parent=parent,
+ urwid.ParentNode.__init__(self, path, key=key, parent=parent,
depth=depth)
def load_parent(self):
@@ -186,7 +186,7 @@
files.append(a)
except OSError, e:
depth = self.get_depth() + 1
- self._children[None] = ErrorNode(self, parent=self, key=None,
+ self._children[None] = ErrorNode(self, parent=self, key=None,
depth=depth)
return [None]
@@ -199,7 +199,7 @@
keys = dirs + files
if len(keys) == 0:
depth=self.get_depth() + 1
- self._children[None] = EmptyNode(self, parent=self, key=None,
+ self._children[None] = EmptyNode(self, parent=self, key=None,
depth=depth)
keys = [None]
return keys
@@ -226,7 +226,7 @@
('body', 'black', 'light gray'),
('flagged', 'black', 'dark green', ('bold','underline')),
('focus', 'light gray', 'dark blue', 'standout'),
- ('flagged focus', 'yellow', 'dark cyan',
+ ('flagged focus', 'yellow', 'dark cyan',
('bold','standout','underline')),
('head', 'yellow', 'black', 'standout'),
('foot', 'light gray', 'black'),
@@ -236,7 +236,7 @@
('flag', 'dark gray', 'light gray'),
('error', 'dark red', 'light gray'),
]
-
+
footer_text = [
('title', "Directory Browser"), " ",
('key', "UP"), ",", ('key', "DOWN"), ",",
@@ -246,12 +246,12 @@
('key', "+"), ",",
('key', "-"), " ",
('key', "LEFT"), " ",
- ('key', "HOME"), " ",
+ ('key', "HOME"), " ",
('key', "END"), " ",
('key', "Q"),
]
-
-
+
+
def __init__(self):
cwd = os.getcwd()
store_initial_cwd(cwd)
@@ -261,17 +261,17 @@
self.footer = urwid.AttrWrap(urwid.Text(self.footer_text),
'foot')
self.view = urwid.Frame(
- urwid.AttrWrap(self.listbox, 'body'),
- header=urwid.AttrWrap(self.header, 'head'),
+ urwid.AttrWrap(self.listbox, 'body'),
+ header=urwid.AttrWrap(self.header, 'head'),
footer=self.footer)
def main(self):
"""Run the program."""
-
+
self.loop = urwid.MainLoop(self.view, self.palette,
unhandled_input=self.unhandled_input)
self.loop.run()
-
+
# on exit, write the flagged filenames to the console
names = [escape_filename_sh(x) for x in get_flagged_names()]
print " ".join(names)
@@ -299,13 +299,13 @@
def get_flagged_names():
"""Return a list of all filenames marked as flagged."""
-
+
l = []
for w in _widget_cache.values():
if w.flagged:
l.append(w.get_node().get_value())
return l
-
+
######
@@ -314,7 +314,7 @@
def store_initial_cwd(name):
"""Store the initial current working directory path components."""
-
+
global _initial_cwd
_initial_cwd = name.split(dir_sep())
@@ -323,14 +323,14 @@
if name is '/':
return True
-
+
l = name.split(dir_sep())
if len(l) > len(_initial_cwd):
return False
-
+
if l != _initial_cwd[:len(l)]:
return False
-
+
return True
@@ -338,11 +338,11 @@
"""Return a hopefully safe shell-escaped version of a filename."""
# check whether we have unprintable characters
- for ch in name:
- if ord(ch) < 32:
+ for ch in name:
+ if ord(ch) < 32:
# found one so use the ansi-c escaping
return escape_filename_sh_ansic(name)
-
+
# all printable characters, so return a double-quoted version
name.replace('\\','\\\\')
name.replace('"','\\"')
@@ -353,7 +353,7 @@
def escape_filename_sh_ansic(name):
"""Return an ansi-c shell-escaped version of a filename."""
-
+
out =[]
# gather the escaped characters into a list
for ch in name:
@@ -363,7 +363,7 @@
out.append('\\\\')
else:
out.append(ch)
-
+
# slap them back together in an ansi-c quote $'...'
return "$'" + "".join(out) + "'"
@@ -383,6 +383,6 @@
return getattr(os.path,'sep','/')
-if __name__=="__main__":
+if __name__=="__main__":
main()
-
+
diff -Nru urwid-1.2.1/examples/calc.py urwid-1.3.0/examples/calc.py
--- urwid-1.2.1/examples/calc.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/calc.py 2014-10-17 20:09:04.000000000 +0200
@@ -44,7 +44,7 @@
def div_or_none(a,b):
"""Divide a by b. Return result or None on divide by zero."""
- if b == 0:
+ if b == 0:
return None
return a/b
@@ -72,8 +72,8 @@
E_cant_combine = "Cannot combine cells with sub-expressions."
E_invalid_in_parent_cell = "Cannot enter numbers into parent cell."
E_invalid_in_help_col = [
- "Help Column is in focus. Press ",
- ('key',COLUMN_KEYS[1]),"-",('key',COLUMN_KEYS[-1]),
+ "Help Column is in focus. Press ",
+ ('key',COLUMN_KEYS[1]),"-",('key',COLUMN_KEYS[-1]),
" to select another column."]
# Shared layout object
@@ -82,12 +82,12 @@
class CalcEvent(Exception):
"""Events triggered by user input."""
-
+
attr = 'event'
-
+
def __init__(self, message):
self.message = message
-
+
def widget(self):
"""Return a widget containing event information"""
text = urwid.Text( self.message, 'center' )
@@ -115,24 +115,24 @@
self.child = None
self.setup_edit()
self.result = urwid.Text("", layout=CALC_LAYOUT)
-
+
def show_result(self, next_cell):
"""Return whether this widget should display its result.
next_cell -- the cell following self or None"""
-
- if self.is_top:
+
+ if self.is_top:
return False
if next_cell is None:
return True
if self.op == "+" and next_cell.op == "+":
return False
return True
-
-
+
+
def setup_edit(self):
"""Create the standard edit widget for this cell."""
-
+
self.edit = urwid.IntEdit()
if not self.is_top:
self.edit.set_caption( self.op + " " )
@@ -140,38 +140,38 @@
def get_value(self):
"""Return the numeric value of the cell."""
-
+
if self.child is not None:
return self.child.get_result()
else:
return long("0"+self.edit.edit_text)
-
+
def get_result(self):
"""Return the numeric result of this cell's operation."""
-
+
if self.is_top:
return self.get_value()
- if self.result.text == "":
+ if self.result.text == "":
return None
return long(self.result.text)
def set_result(self, result):
"""Set the numeric result for this cell."""
-
+
if result == None:
self.result.set_text("")
else:
self.result.set_text( "%d" %result )
-
+
def become_parent(self, column, letter):
"""Change the edit widget to a parent cell widget."""
-
+
self.child = column
self.edit = ParentEdit( self.op, letter )
-
+
def remove_child(self):
"""Change the edit widget back to a standard edit widget."""
-
+
self.child = None
self.setup_edit()
@@ -183,39 +183,39 @@
class ParentEdit(urwid.Edit):
"""Edit widget modified to link to a child column"""
-
+
def __init__(self, op, letter):
"""Use the operator and letter of the child column as caption
-
+
op -- operator or None
letter -- letter of child column
remove_fn -- function to call when user wants to remove child
function takes no parameters
"""
-
+
urwid.Edit.__init__(self, layout=CALC_LAYOUT)
self.op = op
self.set_letter( letter )
-
+
def set_letter(self, letter):
"""Set the letter of the child column for display."""
-
+
self.letter = letter
caption = "("+letter+")"
if self.op is not None:
caption = self.op+" "+caption
self.set_caption(caption)
-
+
def keypress(self, size, key):
- """Disable usual editing, allow only removing of child"""
-
+ """Disable usual editing, allow only removing of child"""
+
if key == "backspace":
raise ColumnDeleteEvent(self.letter, from_parent=True)
elif key in list("0123456789"):
raise CalcEvent, E_invalid_in_parent_cell
else:
return key
-
+
class CellWalker(urwid.ListWalker):
def __init__(self, content):
@@ -243,13 +243,13 @@
return self.div, pos
else:
return self.content[i].result, pos
-
+
def get_focus(self):
return self._get_at_pos(self.focus)
-
+
def set_focus(self, focus):
self.focus = focus
-
+
def get_next(self, start_from):
i, sub = start_from
assert sub in (0,1,2)
@@ -264,7 +264,7 @@
return self._get_at_pos( (i, 2) )
else:
return self._get_at_pos( (i+1, 0) )
-
+
def get_prev(self, start_from):
i, sub = start_from
assert sub in (0,1,2)
@@ -280,8 +280,8 @@
return self._get_at_pos( (i, 0) )
else:
return self._get_at_pos( (i, 1) )
-
-
+
+
class CellColumn( urwid.WidgetWrap ):
def __init__(self, letter):
self.walker = CellWalker([Cell(None)])
@@ -289,55 +289,55 @@
self.listbox = urwid.ListBox( self.walker )
self.set_letter( letter )
urwid.WidgetWrap.__init__(self, self.frame)
-
+
def set_letter(self, letter):
"""Set the column header with letter."""
-
+
self.letter = letter
header = urwid.AttrWrap(
urwid.Text( ["Column ",('key',letter)],
layout = CALC_LAYOUT), 'colhead' )
self.frame = urwid.Frame( self.listbox, header )
-
+
def keypress(self, size, key):
key = self.frame.keypress( size, key)
- if key is None:
+ if key is None:
changed = self.update_results()
if changed:
raise UpdateParentEvent()
return
-
+
f, (i, sub) = self.walker.get_focus()
- if sub != 0:
+ if sub != 0:
# f is not an edit widget
return key
- if OPERATORS.has_key(key):
+ if key in OPERATORS:
# move trailing text to new cell below
edit = self.walker.get_cell(i).edit
cursor_pos = edit.edit_pos
tail = edit.edit_text[cursor_pos:]
edit.set_edit_text( edit.edit_text[:cursor_pos] )
-
+
new_cell = Cell( key )
new_cell.edit.set_edit_text( tail )
self.content[i+1:i+1] = [new_cell]
-
+
changed = self.update_results()
self.move_focus_next( size )
self.content[i+1].edit.set_edit_pos(0)
if changed:
raise UpdateParentEvent()
return
-
+
elif key == 'backspace':
# unhandled backspace, we're at beginning of number
# append current number to cell above, removing operator
above = self.walker.get_cell(i-1)
if above is None:
# we're the first cell
- raise ColumnDeleteEvent( self.letter,
+ raise ColumnDeleteEvent( self.letter,
from_parent=False )
-
+
edit = self.walker.get_cell(i).edit
# check that we can combine
if above.child is not None:
@@ -346,7 +346,7 @@
# ..and current not empty, no good
raise CalcEvent, E_cant_combine
above_pos = 0
- else:
+ else:
# above is normal number cell
above_pos = len(above.edit.edit_text)
above.edit.set_edit_text( above.edit.edit_text +
@@ -359,7 +359,7 @@
if changed:
raise UpdateParentEvent()
return
-
+
elif key == 'delete':
# pull text from next cell into current
cell = self.walker.get_cell(i)
@@ -373,7 +373,7 @@
if below.child is not None:
# cell below is a parent
raise CalcEvent, E_cant_combine
-
+
edit = self.walker.get_cell(i).edit
edit.set_edit_text( edit.edit_text +
below.edit.edit_text )
@@ -385,53 +385,53 @@
return
return key
-
+
def move_focus_next(self, size):
f, (i, sub) = self.walker.get_focus()
assert i<len(self.content)-1
-
+
ni = i
while ni == i:
self.frame.keypress(size, 'down')
nf, (ni, nsub) = self.walker.get_focus()
-
+
def move_focus_prev(self, size):
f, (i, sub) = self.walker.get_focus()
assert i>0
-
+
ni = i
while ni == i:
self.frame.keypress(size, 'up')
nf, (ni, nsub) = self.walker.get_focus()
-
-
+
+
def update_results( self, start_from=None ):
"""Update column. Return True if final result changed.
-
+
start_from -- Cell to start updating from or None to start from
the current focus (default None)
"""
-
+
if start_from is None:
f, (i, sub) = self.walker.get_focus()
else:
i = self.content.index(start_from)
if i == None: return False
-
+
focus_cell = self.walker.get_cell(i)
-
+
if focus_cell.is_top:
x = focus_cell.get_value()
last_op = None
- else:
+ else:
last_cell = self.walker.get_cell(i-1)
x = last_cell.get_result()
-
+
if x is not None and focus_cell.op is not None:
- x = OPERATORS[focus_cell.op]( x,
+ x = OPERATORS[focus_cell.op]( x,
focus_cell.get_value() )
focus_cell.set_result(x)
-
+
for cell in self.content[i+1:]:
if cell.op is None:
x = None
@@ -443,11 +443,11 @@
return True
-
+
def create_child( self, letter ):
"""Return (parent cell,child column) or None,None on failure."""
f, (i, sub) = self.walker.get_focus()
- if sub != 0:
+ if sub != 0:
# f is not an edit widget
return None, None
@@ -467,10 +467,10 @@
return len(self.content)==1 and self.content[0].is_empty()
-
+
def get_expression(self):
"""Return the expression as a printable string."""
-
+
l = []
for c in self.content:
if c.op is not None: # only applies to first cell
@@ -479,16 +479,16 @@
l.append("("+c.child.get_expression()+")")
else:
l.append("%d"%c.get_value())
-
+
return "".join(l)
def get_result(self):
"""Return the result of the last cell in the column."""
-
+
return self.content[-1].get_result()
-
-
+
+
class HelpColumn(urwid.BoxWidget):
help_text = [
@@ -507,8 +507,8 @@
"",
[ "Sub-expressions: ", ('key', "("), " and ", ('key', ")") ],
"",
- [ "Columns: ", ('key', COLUMN_KEYS[0]), " and ",
- ('key',COLUMN_KEYS[1]), "-",
+ [ "Columns: ", ('key', COLUMN_KEYS[0]), " and ",
+ ('key',COLUMN_KEYS[1]), "-",
('key',COLUMN_KEYS[-1]) ],
"",
[ "Exit: ", ('key', "Q") ],
@@ -516,39 +516,39 @@
"",
["Column Calculator does operations in the order they are ",
"typed, not by following usual precedence rules. ",
- "If you want to calculate ", ('key', "12 - 2 * 3"),
+ "If you want to calculate ", ('key', "12 - 2 * 3"),
" with the multiplication happening before the ",
- "subtraction you must type ",
+ "subtraction you must type ",
('key', "12 - (2 * 3)"), " instead."],
]
-
+
def __init__(self):
self.head = urwid.AttrWrap(
urwid.Text(["Help Column ", ('key',"?")],
layout = CALC_LAYOUT),
'help')
- self.foot = urwid.AttrWrap(
+ self.foot = urwid.AttrWrap(
urwid.Text(["[text continues.. press ",
('key',"?"), " then scroll]"]), 'helpnote' )
self.items = [urwid.Text(x) for x in self.help_text]
self.listbox = urwid.ListBox(urwid.SimpleListWalker(self.items))
self.body = urwid.AttrWrap( self.listbox, 'help' )
self.frame = urwid.Frame( self.body, header=self.head)
-
+
def render(self, size, focus=False):
maxcol, maxrow = size
head_rows = self.head.rows((maxcol,))
- if "bottom" in self.listbox.ends_visible(
+ if "bottom" in self.listbox.ends_visible(
(maxcol, maxrow-head_rows) ):
self.frame.footer = None
else:
self.frame.footer = self.foot
return self.frame.render( (maxcol, maxrow), focus)
-
+
def keypress( self, size, key ):
return self.frame.keypress( size, key )
-
+
class CalcDisplay:
palette = [
@@ -563,7 +563,7 @@
('event', 'light red', 'black', 'standout'),
('confirm', 'yellow', 'black', 'bold'),
]
-
+
def __init__(self):
self.columns = urwid.Columns([HelpColumn(), CellColumn("A")], 1)
self.col_list = self.columns.widget_list
@@ -586,7 +586,7 @@
def input_filter(self, input, raw_input):
if 'q' in input or 'Q' in input:
raise urwid.ExitMainLoop()
-
+
# handle other keystrokes
for k in input:
try:
@@ -597,51 +597,51 @@
# display any message
self.event = e
self.view.footer = e.widget()
-
+
# remove all input from further processing by MainLoop
return []
-
+
def wrap_keypress(self, key):
"""Handle confirmation and throw event on bad input."""
-
+
try:
key = self.keypress(key)
-
+
except ColumnDeleteEvent, e:
if e.letter == COLUMN_KEYS[1]:
# cannot delete the first column, ignore key
return
-
+
if not self.column_empty( e.letter ):
# need to get two in a row, so check last event
if not isinstance(self.event,ColumnDeleteEvent):
# ask for confirmation
raise e
self.delete_column(e.letter)
-
+
except UpdateParentEvent, e:
self.update_parent_columns()
return
-
+
if key is None:
return
if self.columns.get_focus_column() == 0:
if key not in ('up','down','page up','page down'):
raise CalcEvent, E_invalid_in_help_col
-
+
if key not in EDIT_KEYS and key not in MOVEMENT_KEYS:
raise CalcEvent, E_invalid_key % key.upper()
-
+
def keypress(self, key):
"""Handle a keystroke."""
self.loop.process_input([key])
-
+
if key.upper() in COLUMN_KEYS:
# column switch
i = COLUMN_KEYS.index(key.upper())
- if i >= len( self.col_list ):
+ if i >= len( self.col_list ):
raise CalcEvent, E_no_such_column % key.upper()
self.columns.set_focus_column( i )
return
@@ -650,7 +650,7 @@
if len( self.col_list ) >= len(COLUMN_KEYS):
raise CalcEvent, E_no_more_columns
i = self.columns.get_focus_column()
- if i == 0:
+ if i == 0:
# makes no sense in help column
return key
col = self.col_list[i]
@@ -662,7 +662,7 @@
self.col_list.append(child)
self.set_link( parent, col, child )
self.columns.set_focus_column(len(self.col_list)-1)
-
+
elif key == ")":
i = self.columns.get_focus_column()
if i == 0:
@@ -670,43 +670,43 @@
return key
col = self.col_list[i]
parent, pcol = self.get_parent( col )
- if parent is None:
+ if parent is None:
# column has no parent
raise CalcEvent, E_no_parent_column
-
+
new_i = self.col_list.index( pcol )
self.columns.set_focus_column( new_i )
else:
return key
-
+
def set_link( self, parent, pcol, child ):
"""Store the link between a parent cell and child column.
-
+
parent -- parent Cell object
pcol -- CellColumn where parent resides
child -- child CellColumn object"""
self.col_link[ child ] = parent, pcol
-
+
def get_parent( self, child ):
"""Return the parent and parent column for a given column."""
return self.col_link.get( child, (None,None) )
-
+
def column_empty(self, letter):
"""Return True if the column passed is empty."""
-
+
i = COLUMN_KEYS.index(letter)
col = self.col_list[i]
return col.is_empty()
-
-
+
+
def delete_column(self, letter):
"""Delete the column with the given letter."""
-
+
i = COLUMN_KEYS.index(letter)
col = self.col_list[i]
-
+
parent, pcol = self.get_parent( col )
f = self.columns.get_focus_column()
@@ -714,11 +714,11 @@
# move focus to the parent column
f = self.col_list.index(pcol)
self.columns.set_focus_column(f)
-
+
parent.remove_child()
pcol.update_results(parent)
del self.col_list[i]
-
+
# delete children of this column
keep_right_cols = []
remove_cols = [col]
@@ -732,7 +732,7 @@
# remove the links
del self.col_link[rc]
# keep only the non-children
- self.col_list[i:] = keep_right_cols
+ self.col_list[i:] = keep_right_cols
# fix the letter assignments
for j in range(i, len(self.col_list)):
@@ -750,21 +750,21 @@
col = self.col_list[f]
while 1:
parent, pcol = self.get_parent(col)
- if pcol is None:
+ if pcol is None:
return
changed = pcol.update_results( start_from = parent )
- if not changed:
+ if not changed:
return
col = pcol
-
-
+
+
def get_expression_result(self):
"""Return (expression, result) as strings."""
-
+
col = self.col_list[1]
return col.get_expression(), "%d"%col.get_result()
-
+
class CalcNumLayout(urwid.TextLayout):
@@ -800,19 +800,19 @@
return l
-
-
-
+
+
+
def main():
"""Launch Column Calculator."""
global CALC_LAYOUT
CALC_LAYOUT = CalcNumLayout()
-
+
urwid.web_display.set_preferences("Column Calculator")
# try to handle short web requests quickly
if urwid.web_display.handle_short_request():
return
-
+
CalcDisplay().main()
if '__main__'==__name__ or urwid.web_display.is_web_request():
diff -Nru urwid-1.2.1/examples/dialog.py urwid-1.3.0/examples/dialog.py
--- urwid-1.2.1/examples/dialog.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/dialog.py 2014-10-17 20:09:04.000000000 +0200
@@ -42,7 +42,7 @@
('focus','white','dark blue','bold'),
('focustext','light gray','dark blue'),
]
-
+
def __init__(self, text, height, width, body=None):
width = int(width)
if width <= 0:
@@ -50,7 +50,7 @@
height = int(height)
if height <= 0:
height = ('relative', 80)
-
+
self.body = body
if body is None:
# fill space with nothing
@@ -61,24 +61,24 @@
self.frame.header = urwid.Pile( [urwid.Text(text),
urwid.Divider()] )
w = self.frame
-
+
# pad area around listbox
w = urwid.Padding(w, ('fixed left',2), ('fixed right',2))
w = urwid.Filler(w, ('fixed top',1), ('fixed bottom',1))
w = urwid.AttrWrap(w, 'body')
-
+
# "shadow" effect
w = urwid.Columns( [w,('fixed', 2, urwid.AttrWrap(
urwid.Filler(urwid.Text(('border',' ')), "top")
,'shadow'))])
- w = urwid.Frame( w, footer =
+ w = urwid.Frame( w, footer =
urwid.AttrWrap(urwid.Text(('border',' ')),'shadow'))
# outermost border area
w = urwid.Padding(w, 'center', width )
w = urwid.Filler(w, 'middle', height )
w = urwid.AttrWrap( w, 'border' )
-
+
self.view = w
@@ -102,10 +102,10 @@
self.loop.run()
except DialogExit, e:
return self.on_exit( e.args[0] )
-
+
def on_exit(self, exitcode):
return exitcode, ""
-
+
class InputDialogDisplay(DialogDisplay):
@@ -113,11 +113,11 @@
self.edit = urwid.Edit()
body = urwid.ListBox([self.edit])
body = urwid.AttrWrap(body, 'selectable','focustext')
-
+
DialogDisplay.__init__(self, text, height, width, body)
-
+
self.frame.set_focus('body')
-
+
def unhandled_key(self, size, k):
if k in ('up','page up'):
self.frame.set_focus('body')
@@ -127,11 +127,11 @@
# pass enter to the "ok" button
self.frame.set_focus('footer')
self.view.keypress( size, k )
-
+
def on_exit(self, exitcode):
return exitcode, self.edit.get_edit_text()
-
+
class TextDialogDisplay(DialogDisplay):
def __init__(self, file, height, width):
l = []
@@ -154,20 +154,20 @@
class ListDialogDisplay(DialogDisplay):
def __init__(self, text, height, width, constr, items, has_default):
j = []
- if has_default:
+ if has_default:
k, tail = 3, ()
- else:
+ else:
k, tail = 2, ("no",)
while items:
j.append( items[:k] + tail )
items = items[k:]
-
+
l = []
self.items = []
for tag, item, default in j:
w = constr( tag, default=="on" )
self.items.append(w)
- w = urwid.Columns( [('fixed', 12, w),
+ w = urwid.Columns( [('fixed', 12, w),
urwid.Text(item)], 2 )
w = urwid.AttrWrap(w, 'selectable','focus')
l.append(w)
@@ -175,9 +175,9 @@
lb = urwid.ListBox(l)
lb = urwid.AttrWrap( lb, "selectable" )
DialogDisplay.__init__(self, text, height, width, lb )
-
+
self.frame.set_focus('body')
-
+
def unhandled_key(self, size, k):
if k in ('up','page up'):
self.frame.set_focus('body')
@@ -199,14 +199,14 @@
s = i.get_label()
break
return exitcode, s
-
-
-
+
+
+
class CheckListDialogDisplay(ListDialogDisplay):
def on_exit(self, exitcode):
"""
- Mimic dialog(1)'s --checklist exit.
+ Mimic dialog(1)'s --checklist exit.
Put each checked item in double quotes with a trailing space.
"""
if exitcode != 0:
@@ -250,7 +250,7 @@
d = CheckListDialogDisplay( text, height, width, constr, items, True)
d.add_buttons([ ("OK", 0), ("Cancel", 1) ])
return d
-
+
def do_inputbox(text, height, width):
d = InputDialogDisplay( text, height, width )
d.add_buttons([ ("Exit", 0) ])
@@ -286,22 +286,22 @@
d.add_buttons([ ("Yes", 0), ("No", 1) ])
return d
-MODES={ '--checklist': (do_checklist,
+MODES={ '--checklist': (do_checklist,
"text height width list-height [ tag item status ] ..."),
- '--inputbox': (do_inputbox,
+ '--inputbox': (do_inputbox,
"text height width"),
- '--menu': (do_menu,
+ '--menu': (do_menu,
"text height width menu-height [ tag item ] ..."),
- '--msgbox': (do_msgbox,
+ '--msgbox': (do_msgbox,
"text height width"),
- '--radiolist': (do_radiolist,
+ '--radiolist': (do_radiolist,
"text height width list-height [ tag item status ] ..."),
'--textbox': (do_textbox,
"file height width"),
- '--yesno': (do_yesno,
+ '--yesno': (do_yesno,
"text height width"),
}
-
+
def show_usage():
"""
@@ -310,7 +310,7 @@
modelist = [(mode, help) for (mode, (fn, help)) in MODES.items()]
modelist.sort()
sys.stdout.write(
- __doc__ +
+ __doc__ +
"\n".join(["%-15s %s"%(mode,help) for (mode,help) in modelist])
+ """
@@ -321,23 +321,23 @@
def main():
- if len(sys.argv) < 2 or not MODES.has_key(sys.argv[1]):
+ if len(sys.argv) < 2 or sys.argv[1] not in MODES:
show_usage()
return
-
+
# Create a DialogDisplay instance
fn, help = MODES[sys.argv[1]]
d = fn( * sys.argv[2:] )
-
+
# Run it
exitcode, exitstring = d.main()
-
+
# Exit
if exitstring:
sys.stderr.write(exitstring+"\n")
-
+
sys.exit(exitcode)
-
-if __name__=="__main__":
+
+if __name__=="__main__":
main()
diff -Nru urwid-1.2.1/examples/edit.py urwid-1.3.0/examples/edit.py
--- urwid-1.2.1/examples/edit.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/edit.py 2014-10-17 20:09:04.000000000 +0200
@@ -37,30 +37,30 @@
class LineWalker(urwid.ListWalker):
"""ListWalker-compatible class for lazily reading file contents."""
-
+
def __init__(self, name):
self.file = open(name)
self.lines = []
self.focus = 0
-
- def get_focus(self):
+
+ def get_focus(self):
return self._get_at_pos(self.focus)
-
+
def set_focus(self, focus):
self.focus = focus
self._modified()
-
+
def get_next(self, start_from):
return self._get_at_pos(start_from + 1)
-
+
def get_prev(self, start_from):
return self._get_at_pos(start_from - 1)
def read_next_line(self):
"""Read another line from the file."""
-
+
next_line = self.file.readline()
-
+
if not next_line or next_line[-1:] != '\n':
# no newline on last line of file
self.file = None
@@ -69,22 +69,22 @@
next_line = next_line[:-1]
expanded = next_line.expandtabs()
-
+
edit = urwid.Edit("", expanded, allow_tab=True)
edit.set_edit_pos(0)
edit.original_text = next_line
self.lines.append(edit)
return next_line
-
-
+
+
def _get_at_pos(self, pos):
"""Return a widget for the line number passed."""
-
+
if pos < 0:
# line 0 is the start of the file, no more above
return None, None
-
+
if len(self.lines) > pos:
# we have that line so return it
return self.lines[pos], pos
@@ -96,12 +96,12 @@
assert pos == len(self.lines), "out of order request?"
self.read_next_line()
-
+
return self.lines[-1], pos
-
+
def split_focus(self):
"""Divide the focus edit widget at the cursor location."""
-
+
focus = self.lines[self.focus]
pos = focus.edit_pos
edit = urwid.Edit("",focus.edit_text[pos:], allow_tab=True)
@@ -117,7 +117,7 @@
if above is None:
# already at the top
return
-
+
focus = self.lines[self.focus]
above.set_edit_pos(len(above.edit_text))
above.set_edit_text(above.edit_text + focus.edit_text)
@@ -131,7 +131,7 @@
if below is None:
# already at bottom
return
-
+
focus = self.lines[self.focus]
focus.set_edit_text(focus.edit_text + below.edit_text)
del self.lines[self.focus+1]
@@ -143,16 +143,16 @@
('foot','dark cyan', 'dark blue', 'bold'),
('key','light cyan', 'dark blue', 'underline'),
]
-
+
footer_text = ('foot', [
"Text Editor ",
('key', "F5"), " save ",
('key', "F8"), " quit",
])
-
+
def __init__(self, name):
self.save_name = name
- self.walker = LineWalker(name)
+ self.walker = LineWalker(name)
self.listbox = urwid.ListBox(self.walker)
self.footer = urwid.AttrWrap(urwid.Text(self.footer_text),
"foot")
@@ -163,7 +163,7 @@
self.loop = urwid.MainLoop(self.view, self.palette,
unhandled_input=self.unhandled_keypress)
self.loop.run()
-
+
def unhandled_keypress(self, k):
"""Last resort for keypresses."""
@@ -197,11 +197,11 @@
else:
return
return True
-
+
def save_file(self):
"""Write the file out to disk."""
-
+
l = []
walk = self.walker
for edit in walk.lines:
@@ -210,14 +210,14 @@
l.append(edit.original_text)
else:
l.append(re_tab(edit.edit_text))
-
+
# then the rest
while walk.file is not None:
l.append(walk.read_next_line())
-
+
# write back to disk
outfile = open(self.save_name, "w")
-
+
prefix = ""
for line in l:
outfile.write(prefix + line)
@@ -249,7 +249,7 @@
sys.stderr.write(__doc__)
return
EditDisplay(name).main()
-
-if __name__=="__main__":
+
+if __name__=="__main__":
main()
diff -Nru urwid-1.2.1/examples/fib.py urwid-1.3.0/examples/fib.py
--- urwid-1.2.1/examples/fib.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/fib.py 2014-10-17 20:09:04.000000000 +0200
@@ -28,32 +28,32 @@
"""
import urwid
-
+
class FibonacciWalker(urwid.ListWalker):
"""ListWalker-compatible class for browsing fibonacci set.
-
+
positions returned are (value at position-1, value at position) tuples.
"""
def __init__(self):
self.focus = (0L,1L)
self.numeric_layout = NumericLayout()
-
+
def _get_at_pos(self, pos):
"""Return a widget and the position passed."""
return urwid.Text("%d"%pos[1], layout=self.numeric_layout), pos
-
- def get_focus(self):
+
+ def get_focus(self):
return self._get_at_pos(self.focus)
-
+
def set_focus(self, focus):
self.focus = focus
self._modified()
-
+
def get_next(self, start_from):
a, b = start_from
focus = b, a+b
return self._get_at_pos(focus)
-
+
def get_prev(self, start_from):
a, b = start_from
focus = b-a, a
@@ -66,7 +66,7 @@
('key','light cyan', 'black', 'underline'),
('title', 'white', 'black',),
]
-
+
footer_text = [
('title', "Fibonacci Set Viewer"), " ",
('key', "UP"), ", ", ('key', "DOWN"), ", ",
@@ -74,7 +74,7 @@
" move view ",
('key', "Q"), " exits",
]
-
+
def exit_on_q(input):
if input in ('q', 'Q'):
raise urwid.ExitMainLoop()
@@ -108,5 +108,5 @@
return [[(width, x, x+width)] for x in linestarts]
-if __name__=="__main__":
+if __name__=="__main__":
main()
diff -Nru urwid-1.2.1/examples/graph.py urwid-1.3.0/examples/graph.py
--- urwid-1.2.1/examples/graph.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/graph.py 2014-10-17 20:09:04.000000000 +0200
@@ -20,7 +20,7 @@
# Urwid web site: http://excess.org/urwid/
"""
-Urwid example demonstrating use of the BarGraph widget and creating a
+Urwid example demonstrating use of the BarGraph widget and creating a
floating-window appearance. Also shows use of alarms to create timed
animation.
"""
@@ -33,12 +33,12 @@
UPDATE_INTERVAL = 0.2
def sin100( x ):
- """
+ """
A sin function that returns values between 0 and 100 and repeats
after x == 100.
"""
return 50 + 50 * math.sin( x * math.pi / 50 )
-
+
class GraphModel:
"""
A class responsible for storing the data that will be displayed
@@ -46,14 +46,14 @@
"""
data_max_value = 100
-
+
def __init__(self):
data = [ ('Saw', range(0,100,2)*2),
('Square', [0]*30 + [100]*30),
('Sine 1', [sin100(x) for x in range(100)] ),
- ('Sine 2', [(sin100(x) + sin100(x*2))/2
+ ('Sine 2', [(sin100(x) + sin100(x*2))/2
for x in range(100)] ),
- ('Sine 3', [(sin100(x) + sin100(x*3))/2
+ ('Sine 3', [(sin100(x) + sin100(x*3))/2
for x in range(100)] ),
]
self.modes = []
@@ -61,13 +61,13 @@
for m, d in data:
self.modes.append(m)
self.data[m] = d
-
+
def get_modes(self):
return self.modes
-
+
def set_mode(self, m):
self.current_mode = m
-
+
def get_data(self, offset, r):
"""
Return the data in [offset:offset+r], the maximum value
@@ -108,11 +108,11 @@
('pg complete', 'white', 'dark magenta'),
('pg smooth', 'dark magenta','black')
]
-
+
graph_samples_per_bar = 10
graph_num_bars = 5
graph_offset_per_second = 5
-
+
def __init__(self, controller):
self.controller = controller
self.started = True
@@ -146,7 +146,7 @@
else:
l.append([value,0])
self.graph.set_data(l,max_value)
-
+
# also update progress
if (o//repeat)&1:
# show 100% for first half, 0 for second half
@@ -171,8 +171,8 @@
self.started = True
self.start_time = time.time()
self.controller.animate_graph()
-
-
+
+
def on_reset_button(self, w):
self.offset = 0
self.start_time = time.time()
@@ -199,13 +199,13 @@
self.animate_progress = self.progress_bar( state )
self.animate_progress_wrap._w = self.animate_progress
self.update_graph( True )
-
+
def main_shadow(self, w):
"""Wrap a shadow and background around widget w."""
bg = urwid.AttrWrap(urwid.SolidFill(u"\u2592"), 'screen edge')
shadow = urwid.AttrWrap(urwid.SolidFill(u" "), 'main shadow')
-
+
bg = urwid.Overlay( shadow, bg,
('fixed left', 3), ('fixed right', 1),
('fixed top', 2), ('fixed bottom', 1))
@@ -213,7 +213,7 @@
('fixed left', 2), ('fixed right', 3),
('fixed top', 1), ('fixed bottom', 2))
return w
-
+
def bar_graph(self, smooth=False):
satt = None
if smooth:
@@ -233,7 +233,7 @@
def progress_bar(self, smooth=False):
if smooth:
- return urwid.ProgressBar('pg normal', 'pg complete',
+ return urwid.ProgressBar('pg normal', 'pg complete',
0, 1, 'pg smooth')
else:
return urwid.ProgressBar('pg normal', 'pg complete',
@@ -255,11 +255,11 @@
self.on_animate_button( self.animate_button )
self.offset = 0
self.animate_progress = self.progress_bar()
- animate_controls = urwid.GridFlow( [
+ animate_controls = urwid.GridFlow( [
self.animate_button,
self.button("Reset", self.on_reset_button),
], 9, 2, 0, 'center')
-
+
if urwid.get_encoding_mode() == "utf8":
unicode_checkbox = urwid.CheckBox(
"Enable Unicode Graphics",
@@ -267,10 +267,10 @@
else:
unicode_checkbox = urwid.Text(
"UTF-8 encoding not detected")
-
+
self.animate_progress_wrap = urwid.WidgetWrap(
self.animate_progress)
-
+
l = [ urwid.Text("Mode",align="center"),
] + self.mode_buttons + [
urwid.Divider(),
@@ -285,7 +285,7 @@
w = urwid.ListBox(urwid.SimpleListWalker(l))
return w
- def main_window(self):
+ def main_window(self):
self.graph = self.bar_graph()
self.graph_wrap = urwid.WidgetWrap( self.graph )
vline = urwid.AttrWrap( urwid.SolidFill(u'\u2502'), 'line')
@@ -299,7 +299,7 @@
w = urwid.AttrWrap(w,'line')
w = self.main_shadow(w)
return w
-
+
class GraphController:
"""
@@ -320,17 +320,17 @@
def get_modes(self):
"""Allow our view access to the list of modes."""
return self.model.get_modes()
-
+
def set_mode(self, m):
"""Allow our view to set the mode."""
rval = self.model.set_mode( m )
self.view.update_graph(True)
return rval
-
+
def get_data(self, offset, range):
"""Provide data to our view for the graph."""
return self.model.get_data( offset, range )
-
+
def main(self):
self.loop = urwid.MainLoop(self.view, self.view.palette)
@@ -347,10 +347,10 @@
if self.animate_alarm:
self.loop.remove_alarm(self.animate_alarm)
self.animate_alarm = None
-
+
def main():
GraphController().main()
-
+
if '__main__'==__name__:
main()
diff -Nru urwid-1.2.1/examples/input_test.py urwid-1.3.0/examples/input_test.py
--- urwid-1.2.1/examples/input_test.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/input_test.py 2014-10-17 20:09:04.000000000 +0200
@@ -63,9 +63,9 @@
t += ["("] + out + [")"]
else:
t += ["'",('key',k),"' "]
-
+
rawt = urwid.Text(", ".join(["%d"%r for r in raw]))
-
+
if t:
lw.append(
urwid.Columns([
@@ -87,8 +87,8 @@
loop.run()
finally:
screen.tty_signal_keys(*old)
-
-
+
+
def main():
@@ -96,7 +96,7 @@
if urwid.web_display.handle_short_request():
return
key_test()
-
+
if '__main__'==__name__ or urwid.web_display.is_web_request():
main()
diff -Nru urwid-1.2.1/examples/lcd_cf635.py urwid-1.3.0/examples/lcd_cf635.py
--- urwid-1.2.1/examples/lcd_cf635.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/lcd_cf635.py 2014-10-17 20:09:04.000000000 +0200
@@ -13,7 +13,7 @@
...... ...... ......
0x11 0xd0 0xbb
-By adding the characters in CGRAM below we can use them as part of a
+By adding the characters in CGRAM below we can use them as part of a
horizontal slider control, selected check box and selected radio button
respectively.
"""
@@ -22,14 +22,14 @@
import urwid.lcd_display
CGRAM = """
-...... ...... ...... ...... ..X... ...... ...... ......
-XXXXXX XXXXXX XXXXXX XXXXXX X.XX.. .XXXXX ..XXX. .....X
-...... XX.... XXXX.. XXXXXX X.XXX. .X...X .X...X ....XX
-...... XX.... XXXX.. XXXXXX X.XXXX .X...X .X...X .X.XX.
-...... XX.... XXXX.. XXXXXX X.XXX. .X...X .X...X .XXX..
-XXXXXX XXXXXX XXXXXX XXXXXX X.XX.. .XXXXX ..XXX. ..X...
-...... ...... ...... ...... ..X... ...... ...... ......
-...... ...... ...... ...... ...... ...... ...... ......
+...... ...... ...... ...... ..X... ...... ...... ......
+XXXXXX XXXXXX XXXXXX XXXXXX X.XX.. .XXXXX ..XXX. .....X
+...... XX.... XXXX.. XXXXXX X.XXX. .X...X .X...X ....XX
+...... XX.... XXXX.. XXXXXX X.XXXX .X...X .X...X .X.XX.
+...... XX.... XXXX.. XXXXXX X.XXX. .X...X .X...X .XXX..
+XXXXXX XXXXXX XXXXXX XXXXXX X.XX.. .XXXXX ..XXX. ..X...
+...... ...... ...... ...... ..X... ...... ...... ......
+...... ...... ...... ...... ...... ...... ...... ......
"""
def program_cgram(screen):
@@ -94,11 +94,11 @@
filled = urwid.int_scale(self.value, self.range, steps)
full_segments = int(filled / (len(self.segments) - 1))
last_char = filled % (len(self.segments) - 1) + 1
- s = (self.segments[-1] * full_segments +
+ s = (self.segments[-1] * full_segments +
self.segments[last_char] +
self.segments[0] * (maxcol -full_segments - 1))
return urwid.Text(s).render(size)
-
+
def move_position(self, size, direction):
"""
Update and return the value one step +ve or -ve, based on
@@ -166,7 +166,7 @@
('fixed', 1, urwid.SelectableIcon('\xdf', cursor_position=0)),
self._label])
- urwid.connect_signal(self, 'click',
+ urwid.connect_signal(self, 'click',
lambda option: show_menu(submenu))
def keypress(self, size, key):
@@ -214,10 +214,10 @@
apply an exponential transformation to values sent so
that apparent brightness increases in a natural way.
"""
- return lambda value: screen.set_led_pin(index, rg,
- [0, 1, 2, 3, 4, 5, 6, 8, 11, 14, 18,
+ return lambda value: screen.set_led_pin(index, rg,
+ [0, 1, 2, 3, 4, 5, 6, 8, 11, 14, 18,
23, 29, 38, 48, 61, 79, 100][value])
-
+
return urwid.Columns([
('fixed', 2, urwid.Text('%dR' % index)),
LCDHorizontalSlider(18, 0, exp_scale_led(0)),
@@ -228,15 +228,15 @@
menu_structure = [
('Display Settings', [
display_setting('Brightness', 101, screen.set_backlight),
- display_setting('Contrast', 76,
+ display_setting('Contrast', 76,
lambda x: screen.set_lcd_contrast(x + 75)),
]),
('Cursor Settings', [
cursor_option('Block', screen.CURSOR_BLINKING_BLOCK),
cursor_option('Underscore', screen.CURSOR_UNDERSCORE),
- cursor_option('Block + Underscore',
+ cursor_option('Block + Underscore',
screen.CURSOR_BLINKING_BLOCK_UNDERSCORE),
- cursor_option('Inverting Block',
+ cursor_option('Inverting Block',
screen.CURSOR_INVERTING_BLINKING_BLOCK),
]),
('LEDs', [
@@ -279,7 +279,7 @@
# set up our font
program_cgram(screen)
loop = urwid.MainLoop(build_menus(), screen=screen)
-# FIXME: want screen to know it is in narrow mode, or better yet,
+# FIXME: want screen to know it is in narrow mode, or better yet,
# do the unicode conversion for us
urwid.set_encoding('narrow')
diff -Nru urwid-1.2.1/examples/palette_test.py urwid-1.3.0/examples/palette_test.py
--- urwid-1.2.1/examples/palette_test.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/palette_test.py 2014-10-17 20:09:04.000000000 +0200
@@ -34,10 +34,10 @@
brown__ dark_red_ dark_magenta_ dark_blue_ dark_cyan_ dark_green_
yellow_ light_red light_magenta light_blue light_cyan light_green
- #00f#06f#08f#0af#0df#0ff black_______ dark_gray___
+ #00f#06f#08f#0af#0df#0ff black_______ dark_gray___
#60f#00d#06d#08d#0ad#0dd#0fd light_gray__ white_______
- #80f#60d#00a#06a#08a#0aa#0da#0fa
- #a0f#80d#60a#008#068#088#0a8#0d8#0f8
+ #80f#60d#00a#06a#08a#0aa#0da#0fa
+ #a0f#80d#60a#008#068#088#0a8#0d8#0f8
#d0f#a0d#80d#608#006#066#086#0a6#0d6#0f6
#f0f#d0d#a0a#808#606#000#060#080#0a0#0d0#0f0#0f6#0f8#0fa#0fd#0ff
#f0d#d0a#a08#806#600#660#680#6a0#6d0#6f0#6f6#6f8#6fa#6fd#6ff#0df
@@ -50,29 +50,29 @@
#86d#66a#68a#6aa#6da #f80#f86#f88#f8a#f8d#f8f#d6f#a0f
#a6d#86a#668#688#6a8#6d8 #f60#f66#f68#f6a#f6d#f6f#d0f
#d6d#a6a#868#666#686#6a6#6d6#6d8#6da#6dd #f00#f06#f08#f0a#f0d#f0f
- #d6a#a68#866#886#8a6#8d6#8d8#8da#8dd#6ad
- #d68#a66#a86#aa6#ad6#ad8#ada#add#8ad#68d
- #d66#d86#da6#dd6#dd8#dda#ddd#aad#88d#66d g78_g82_g85_g89_g93_g100
+ #d6a#a68#866#886#8a6#8d6#8d8#8da#8dd#6ad
+ #d68#a66#a86#aa6#ad6#ad8#ada#add#8ad#68d
+ #d66#d86#da6#dd6#dd8#dda#ddd#aad#88d#66d g78_g82_g85_g89_g93_g100
#da6#da8#daa#dad#a8d#86d g52_g58_g62_g66_g70_g74_
#88a#8aa #d86#d88#d8a#d8d#a6d g27_g31_g35_g38_g42_g46_g50_
#a8a#888#8a8#8aa #d66#d68#d6a#d6d g0__g3__g7__g11_g15_g19_g23_
- #a88#aa8#aaa#88a
+ #a88#aa8#aaa#88a
#a88#a8a
-"""
+"""
CHART_88 = """
brown__ dark_red_ dark_magenta_ dark_blue_ dark_cyan_ dark_green_
yellow_ light_red light_magenta light_blue light_cyan light_green
- #00f#08f#0cf#0ff black_______ dark_gray___
- #80f#00c#08c#0cc#0fc light_gray__ white_______
+ #00f#08f#0cf#0ff black_______ dark_gray___
+ #80f#00c#08c#0cc#0fc light_gray__ white_______
#c0f#80c#008#088#0c8#0f8
-#f0f#c0c#808#000#080#0c0#0f0#0f8#0fc#0ff #88c#8cc
- #f0c#c08#800#880#8c0#8f0#8f8#8fc#8ff#0cf #c8c#888#8c8#8cc
+#f0f#c0c#808#000#080#0c0#0f0#0f8#0fc#0ff #88c#8cc
+ #f0c#c08#800#880#8c0#8f0#8f8#8fc#8ff#0cf #c8c#888#8c8#8cc
#f08#c00#c80#cc0#cf0#cf8#cfc#cff#8cf#08f #c88#cc8#ccc#88c
- #f00#f80#fc0#ff0#ff8#ffc#fff#ccf#88f#00f #c88#c8c
- #fc0#fc8#fcc#fcf#c8f#80f
- #f80#f88#f8c#f8f#c0f g62_g74_g82_g89_g100
+ #f00#f80#fc0#ff0#ff8#ffc#fff#ccf#88f#00f #c88#c8c
+ #fc0#fc8#fcc#fcf#c8f#80f
+ #f80#f88#f8c#f8f#c0f g62_g74_g82_g89_g100
#f00#f08#f0c#f0f g0__g19_g35_g46_g52
"""
@@ -80,7 +80,7 @@
brown__ dark_red_ dark_magenta_ dark_blue_ dark_cyan_ dark_green_
yellow_ light_red light_magenta light_blue light_cyan light_green
-black_______ dark_gray___ light_gray__ white_______
+black_______ dark_gray___ light_gray__ white_______
"""
ATTR_RE = re.compile("(?P<whitespace>[ \n]*)(?P<entry>[^ \n]+)")
@@ -115,7 +115,7 @@
attr, text = attrtext
out.append((attr, text.ljust(elen)))
return out
-
+
def foreground_chart(chart, background, colors):
"""
Create text markup for a foreground colour chart
@@ -199,7 +199,7 @@
if state:
is_foreground_chart = chart_radio_buttons[0].state
set_mode(colors, is_foreground_chart)
-
+
def mode_rb(text, colors, state=False):
# mode radio buttons
rb = urwid.RadioButton(mode_radio_buttons, text, state)
@@ -209,10 +209,10 @@
def on_chart_change(rb, state):
# handle foreground check box state change
set_mode(screen.colors, state)
-
+
def click_exit(button):
raise urwid.ExitMainLoop()
-
+
lb.extend([
urwid.AttrMap(urwid.Text("Urwid Palette Test"), 'header'),
urwid.AttrMap(urwid.Columns([
@@ -238,7 +238,7 @@
])
set_mode(16, True) # displays the chart
-
+
def unhandled_input(key):
if key in ('Q','q','esc'):
raise urwid.ExitMainLoop()
diff -Nru urwid-1.2.1/examples/treesample.py urwid-1.3.0/examples/treesample.py
--- urwid-1.2.1/examples/treesample.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/treesample.py 2014-10-17 20:09:04.000000000 +0200
@@ -78,7 +78,7 @@
('flag', 'dark gray', 'light gray'),
('error', 'dark red', 'light gray'),
]
-
+
footer_text = [
('title', "Example Data Browser"), " ",
('key', "UP"), ",", ('key', "DOWN"), ",",
@@ -87,7 +87,7 @@
('key', "+"), ",",
('key', "-"), " ",
('key', "LEFT"), " ",
- ('key', "HOME"), " ",
+ ('key', "HOME"), " ",
('key', "END"), " ",
('key', "Q"),
]
@@ -99,14 +99,14 @@
self.header = urwid.Text( "" )
self.footer = urwid.AttrWrap( urwid.Text( self.footer_text ),
'foot')
- self.view = urwid.Frame(
- urwid.AttrWrap( self.listbox, 'body' ),
- header=urwid.AttrWrap(self.header, 'head' ),
+ self.view = urwid.Frame(
+ urwid.AttrWrap( self.listbox, 'body' ),
+ header=urwid.AttrWrap(self.header, 'head' ),
footer=self.footer )
def main(self):
"""Run the program."""
-
+
self.loop = urwid.MainLoop(self.view, self.palette,
unhandled_input=self.unhandled_input)
self.loop.run()
@@ -123,7 +123,7 @@
retval['children'].append({"name":"child " + str(i)})
retval['children'][i]['children']=[]
for j in range(10):
- retval['children'][i]['children'].append({"name":"grandchild " +
+ retval['children'][i]['children'].append({"name":"grandchild " +
str(i) + "." + str(j)})
return retval
@@ -133,6 +133,6 @@
ExampleTreeBrowser(sample).main()
-if __name__=="__main__":
+if __name__=="__main__":
main()
diff -Nru urwid-1.2.1/examples/twisted_serve_ssh.py urwid-1.3.0/examples/twisted_serve_ssh.py
--- urwid-1.2.1/examples/twisted_serve_ssh.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/examples/twisted_serve_ssh.py 2014-10-17 20:09:04.000000000 +0200
@@ -34,6 +34,7 @@
import os
import urwid
+from urwid.raw_display import Screen
from zope.interface import Interface, Attribute, implements
from twisted.application.service import Application
@@ -159,7 +160,7 @@
-class TwistedScreen(urwid.BaseScreen):
+class TwistedScreen(Screen):
"""A Urwid screen which knows about the Twisted terminal protocol that is
driving it.
@@ -180,7 +181,7 @@
# We will need these later
self.terminalProtocol = terminalProtocol
self.terminal = terminalProtocol.terminal
- urwid.BaseScreen.__init__(self)
+ Screen.__init__(self)
self.colors = 16
self._pal_escape = {}
self.bright_is_bold = True
@@ -235,13 +236,22 @@
# twisted handles polling, so we don't need the loop to do it, we just
# push what we get to the loop from dataReceived.
- def get_input_descriptors(self):
- return []
+ def hook_event_loop(self, event_loop, callback):
+ self._urwid_callback = callback
+ self._evl = event_loop
+
+ def unhook_event_loop(self, event_loop):
+ pass
# Do nothing here either. Not entirely sure when it gets called.
def get_input(self, raw_keys=False):
return
+ def get_available_raw_input(self):
+ data = self._data
+ self._data = []
+ return data
+
# Twisted driven
def push(self, data):
"""Receive data from Twisted and push it into the urwid main loop.
@@ -254,9 +264,8 @@
3. Pass the calculated keys as a list to the Urwid main loop.
4. Redraw the screen
"""
- keys = self.loop.input_filter(data, [])
- keys, remainder = urwid.escape.process_keyqueue(map(ord, keys), True)
- self.loop.process_input(keys)
+ self._data = list(map(ord, data))
+ self.parse_input(self._evl, self._urwid_callback)
self.loop.draw_screen()
# Convenience
diff -Nru urwid-1.2.1/PKG-INFO urwid-1.3.0/PKG-INFO
--- urwid-1.2.1/PKG-INFO 2014-04-04 17:55:41.000000000 +0200
+++ urwid-1.3.0/PKG-INFO 2014-10-17 20:27:53.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: urwid
-Version: 1.2.1
+Version: 1.3.0
Summary: A full-featured console (xterm et al.) user interface library
Home-page: http://urwid.org/
Author: Ian Ward
diff -Nru urwid-1.2.1/urwid/canvas.py urwid-1.3.0/urwid/canvas.py
--- urwid-1.2.1/urwid/canvas.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/canvas.py 2014-10-17 20:09:04.000000000 +0200
@@ -30,13 +30,13 @@
class CanvasCache(object):
"""
Cache for rendered canvases. Automatically populated and
- accessed by Widget render() MetaClass magic, cleared by
+ accessed by Widget render() MetaClass magic, cleared by
Widget._invalidate().
Stores weakrefs to the canvas objects, so an external class
must maintain a reference for this cache to be effective.
- At present the Screen classes store the last topmost canvas
- after redrawing the screen, keeping the canvases from being
+ At present the Screen classes store the last topmost canvas
+ after redrawing the screen, keeping the canvases from being
garbage collected.
_widgets[widget] = {(wcls, size, focus): weakref.ref(canvas), ...}
@@ -67,7 +67,7 @@
Collect all child widgets for determining who we
depend on.
"""
- # FIXME: is this recursion necessary? The cache
+ # FIXME: is this recursion necessary? The cache
# invalidating might work with only one level.
depends = []
for x, y, c, pos in canv.children:
@@ -114,7 +114,7 @@
cls.hits += 1 # more stats
return canv
fetch = classmethod(fetch)
-
+
def invalidate(cls, widget):
"""
Remove all canvases cached for widget.
@@ -172,7 +172,7 @@
clear = classmethod(clear)
-
+
class CanvasError(Exception):
pass
@@ -198,12 +198,12 @@
value1, value2, value3 -- if not None, raise a helpful error:
the old Canvas class is now called TextCanvas.
"""
- if value1 is not None:
+ if value1 is not None:
raise self._renamed_error
self._widget_info = None
self.coords = {}
self.shortcuts = {}
-
+
def finalize(self, widget, size, focus):
"""
Mark this canvas as finalized (should not be any future
@@ -226,7 +226,7 @@
def _raise_old_repr_error(self, val=None):
raise self._old_repr_error
-
+
def _text_content(self):
"""
Return the text content of the canvas as a list of strings,
@@ -238,8 +238,8 @@
text = property(_text_content, _raise_old_repr_error)
attr = property(_raise_old_repr_error, _raise_old_repr_error)
cs = property(_raise_old_repr_error, _raise_old_repr_error)
-
- def content(self, trim_left=0, trim_top=0, cols=None, rows=None,
+
+ def content(self, trim_left=0, trim_top=0, cols=None, rows=None,
attr=None):
raise NotImplementedError()
@@ -248,7 +248,7 @@
def rows(self):
raise NotImplementedError()
-
+
def content_delta(self):
raise NotImplementedError()
@@ -313,7 +313,7 @@
"""
class for storing rendered text and attributes
"""
- def __init__(self, text=None, attr=None, cs=None,
+ def __init__(self, text=None, attr=None, cs=None,
cursor=None, maxcol=None, check_width=True):
"""
text -- list of strings, one for each line
@@ -324,7 +324,7 @@
check_width -- check and fix width of all lines in text
"""
Canvas.__init__(self)
- if text == None:
+ if text == None:
text = []
if check_width:
@@ -344,7 +344,7 @@
else:
maxcol = 0
- if attr == None:
+ if attr == None:
attr = [[] for x in range(len(text))]
if cs == None:
cs = [[] for x in range(len(text))]
@@ -352,7 +352,7 @@
# pad text and attr to maxcol
for i in range(len(text)):
w = widths[i]
- if w > maxcol:
+ if w > maxcol:
raise CanvasError("Canvas text is wider than the maxcol specified \n%r\n%r\n%r"%(maxcol,widths,text))
if w < maxcol:
text[i] = text[i] + bytes().rjust(maxcol-w)
@@ -361,13 +361,13 @@
raise CanvasError("Attribute extends beyond text \n%r\n%r" % (text[i],attr[i]) )
if a_gap:
rle_append_modify( attr[i], (None, a_gap))
-
+
cs_gap = len(text[i]) - rle_len( cs[i] )
if cs_gap < 0:
raise CanvasError("Character Set extends beyond text \n%r\n%r" % (text[i],cs[i]) )
if cs_gap:
rle_append_modify( cs[i], (None, cs_gap))
-
+
self._attr = attr
self._cs = cs
self.cursor = cursor
@@ -383,7 +383,7 @@
def cols(self):
"""Return the screen column width of this canvas."""
return self._maxcol
-
+
def translated_coords(self,dx,dy):
"""
Return cursor coords shifted by (dx, dy), or None if there
@@ -400,33 +400,33 @@
Return the canvas content as a list of rows where each row
is a list of (attr, cs, text) tuples.
- trim_left, trim_top, cols, rows may be set by
+ trim_left, trim_top, cols, rows may be set by
CompositeCanvas when rendering a partially obscured
canvas.
"""
maxcol, maxrow = self.cols(), self.rows()
- if not cols:
+ if not cols:
cols = maxcol - trim_left
if not rows:
rows = maxrow - trim_top
-
+
assert trim_left >= 0 and trim_left < maxcol
assert cols > 0 and trim_left + cols <= maxcol
assert trim_top >=0 and trim_top < maxrow
assert rows > 0 and trim_top + rows <= maxrow
-
+
if trim_top or rows < maxrow:
text_attr_cs = zip(
self._text[trim_top:trim_top+rows],
- self._attr[trim_top:trim_top+rows],
+ self._attr[trim_top:trim_top+rows],
self._cs[trim_top:trim_top+rows])
else:
text_attr_cs = zip(self._text, self._attr, self._cs)
-
+
for text, a_row, cs_row in text_attr_cs:
if trim_left or cols < self._maxcol:
text, a_row, cs_row = trim_text_attr_cs(
- text, a_row, cs_row, trim_left,
+ text, a_row, cs_row, trim_left,
trim_left + cols)
attr_cs = rle_product(a_row, cs_row)
i = 0
@@ -437,20 +437,20 @@
row.append((a, cs, text[i:i+run]))
i += run
yield row
-
+
def content_delta(self, other):
"""
Return the differences between other and this canvas.
- If other is the same object as self this will return no
- differences, otherwise this is the same as calling
+ If other is the same object as self this will return no
+ differences, otherwise this is the same as calling
content().
"""
if other is self:
return [self.cols()]*self.rows()
return self.content()
-
+
class BlankCanvas(Canvas):
@@ -477,10 +477,10 @@
def rows(self):
raise NotImplementedError("BlankCanvas doesn't know its own size!")
-
+
def content_delta(self):
raise NotImplementedError("BlankCanvas doesn't know its own size!")
-
+
blank_canvas = BlankCanvas()
@@ -496,14 +496,14 @@
self._cs = cs[0][0]
self.size = cols, rows
self.cursor = None
-
+
def cols(self):
return self.size[0]
-
+
def rows(self):
return self.size[1]
- def content(self, trim_left=0, trim_top=0, cols=None, rows=None,
+ def content(self, trim_left=0, trim_top=0, cols=None, rows=None,
attr=None):
if cols is None:
cols = self.size[0]
@@ -524,7 +524,7 @@
if other is self:
return [self.cols()]*self.rows()
return self.content()
-
+
@@ -538,15 +538,15 @@
if canv is a CompositeCanvas, make a copy of its contents
"""
- # a "shard" is a (num_rows, list of cviews) tuple, one for
+ # a "shard" is a (num_rows, list of cviews) tuple, one for
# each cview starting in this shard
# a "cview" is a tuple that defines a view of a canvas:
# (trim_left, trim_top, cols, rows, attr_map, canv)
# a "shard tail" is a list of tuples:
- # (col_gap, done_rows, content_iter, cview)
-
+ # (col_gap, done_rows, content_iter, cview)
+
# tuples that define the unfinished cviews that are part of
# shards following the first shard.
Canvas.__init__(self)
@@ -559,7 +559,7 @@
self.shards = canv.shards
else:
self.shards = [(canv.rows(), [
- (0, 0, canv.cols(), canv.rows(),
+ (0, 0, canv.cols(), canv.rows(),
None, canv)])]
self.children = [(0, 0, canv, None)]
self.coords.update(canv.coords)
@@ -583,7 +583,7 @@
assert isinstance(cols, int)
return cols
-
+
def content(self):
"""
Return the canvas content as a list of rows where each row
@@ -598,11 +598,11 @@
for i in range(num_rows):
yield shard_body_row(sbody)
- # prepare next shard tail
+ # prepare next shard tail
shard_tail = shard_body_tail(num_rows, sbody)
-
-
+
+
def content_delta(self, other):
"""
Return the differences between other and this canvas.
@@ -621,7 +621,7 @@
# output rows
row = []
for i in range(num_rows):
- # if whole shard is unchanged, don't keep
+ # if whole shard is unchanged, don't keep
# calling shard_body_row
if len(row) != 1 or type(row[0]) != int:
row = shard_body_row(sbody)
@@ -629,8 +629,8 @@
# prepare next shard tail
shard_tail = shard_body_tail(num_rows, sbody)
-
-
+
+
def trim(self, top, count=None):
"""Trim lines from the top and/or bottom of canvas.
@@ -642,7 +642,7 @@
top, self.rows())
if self.widget_info:
raise self._finalized_error
-
+
if top:
self.shards = shards_trim_top(self.shards, top)
@@ -653,10 +653,10 @@
self.coords = self.translate_coords(0, -top)
-
+
def trim_end(self, end):
"""Trim lines from the bottom of the canvas.
-
+
end -- number of lines to remove from the end
"""
assert end > 0, "invalid trim amount %d!"%end
@@ -664,14 +664,14 @@
end, self.rows())
if self.widget_info:
raise self._finalized_error
-
+
self.shards = shards_trim_rows(self.shards, self.rows() - end)
-
+
def pad_trim_left_right(self, left, right):
"""
Pad or trim this canvas on the left and right
-
+
values > 0 indicate screen columns to pad
values < 0 indicate screen columns to trim
"""
@@ -721,24 +721,24 @@
[(0,0,cols,top,None,blank_canvas)])] + \
self.shards
self.coords = self.translate_coords(0, top)
-
+
if bottom > 0:
if orig_shards is self.shards:
self.shards = self.shards[:]
self.shards.append((bottom,
[(0,0,cols,bottom,None,blank_canvas)]))
-
+
def overlay(self, other, left, top ):
"""Overlay other onto this canvas."""
if self.widget_info:
raise self._finalized_error
-
+
width = other.cols()
height = other.rows()
right = self.cols() - left - width
bottom = self.rows() - top - height
-
+
assert right >= 0, "top canvas of overlay not the size expected!" + repr((other.cols(),left,right,width))
assert bottom >= 0, "top canvas of overlay not the size expected!" + repr((other.rows(),top,bottom,height))
@@ -764,13 +764,13 @@
if not self.rows():
middle_shards = []
elif left or right:
- middle_shards = shards_join(left_shards +
+ middle_shards = shards_join(left_shards +
[other.shards] + right_shards)
else:
middle_shards = other.shards
self.shards = top_shards + middle_shards + bottom_shards
-
+
self.coords.update(other.translate_coords(left, top))
@@ -780,7 +780,7 @@
attribute currently set to None, leaving other attributes
intact."""
self.fill_attr_apply({None:a})
-
+
def fill_attr_apply(self, mapping):
"""
Apply an attribute-mapping dictionary to the canvas.
@@ -796,7 +796,7 @@
for cv in original_cviews:
# cv[4] == attr_map
if cv[4] is None:
- new_cviews.append(cv[:4] +
+ new_cviews.append(cv[:4] +
(mapping,) + cv[5:])
else:
combined = dict(mapping)
@@ -859,7 +859,7 @@
def shards_delta(shards, other_shards):
"""
- Yield shards1 with cviews that are the same as shards2
+ Yield shards1 with cviews that are the same as shards2
having canv = None.
"""
other_shards_iter = iter(other_shards)
@@ -910,11 +910,11 @@
def shard_body(cviews, shard_tail, create_iter=True, iter_default=None):
"""
- Return a list of (done_rows, content_iter, cview) tuples for
+ Return a list of (done_rows, content_iter, cview) tuples for
this shard and shard tail.
- If a canvas in cviews is None (eg. when unchanged from
- shard_cviews_delta()) or if create_iter is False then no
+ If a canvas in cviews is None (eg. when unchanged from
+ shard_cviews_delta()) or if create_iter is False then no
iterator is created for content_iter.
iter_default is the value used for content_iter when no iterator
@@ -938,7 +938,7 @@
raise CanvasError("cviews overflow gaps in"
" shard_tail!")
if create_iter and canv:
- new_iter = canv.content(trim_left, trim_top,
+ new_iter = canv.content(trim_left, trim_top,
cols, rows, attr_map)
else:
new_iter = iter_default
@@ -948,7 +948,7 @@
(trim_left, trim_top, cols, rows, attr_map, canv) = \
cview[:6]
if create_iter and canv:
- new_iter = canv.content(trim_left, trim_top, cols, rows,
+ new_iter = canv.content(trim_left, trim_top, cols, rows,
attr_map)
else:
new_iter = iter_default
@@ -973,19 +973,19 @@
top -= num_rows
else:
raise CanvasError("tried to trim shards out of existence")
-
+
sbody = shard_body(cviews, shard_tail, False)
shard_tail = shard_body_tail(num_rows, sbody)
# trim the top of this shard
new_sbody = []
for done_rows, content_iter, cv in sbody:
- new_sbody.append((0, content_iter,
+ new_sbody.append((0, content_iter,
cview_trim_top(cv, done_rows+top)))
sbody = new_sbody
-
- new_shards = [(num_rows-top,
+
+ new_shards = [(num_rows-top,
[cv for done_rows, content_iter, cv in sbody])]
-
+
# write out the rest of the shards
new_shards.extend(shard_iter)
@@ -1005,7 +1005,7 @@
new_cviews = []
for cv in cviews:
if cv[3] + done_rows > keep_rows:
- new_cviews.append(cview_trim_rows(cv,
+ new_cviews.append(cview_trim_rows(cv,
keep_rows - done_rows))
else:
new_cviews.append(cv)
@@ -1214,13 +1214,13 @@
t = []
a = []
c = []
-
+
class AttrWalk:
pass
aw = AttrWalk
aw.k = 0 # counter for moving through elements of a
aw.off = 0 # current offset into text of attr[ak]
-
+
def arange( start_offs, end_offs ):
"""Return an attribute list for the range of text specified."""
if start_offs < aw.off:
@@ -1246,19 +1246,19 @@
aw.off += run
return o
-
+
for line_layout in ls:
# trim the line to fit within maxcol
line_layout = trim_line( line_layout, text, 0, maxcol )
-
+
line = []
linea = []
linec = []
-
+
def attrrange( start_offs, end_offs, destw ):
"""
Add attributes based on attributes between
- start_offs and end_offs.
+ start_offs and end_offs.
"""
if start_offs == end_offs:
[(at,run)] = arange(start_offs,end_offs)
@@ -1277,12 +1277,12 @@
tseg = text[o:o+run]
tseg, cs = apply_target_encoding( tseg )
segw = rle_len(cs)
-
+
rle_append_modify( linea, ( at, segw ))
o += run
destw -= segw
-
-
+
+
for seg in line_layout:
#if seg is None: assert 0, ls
s = LayoutSegment(seg)
diff -Nru urwid-1.2.1/urwid/container.py urwid-1.3.0/urwid/container.py
--- urwid-1.2.1/urwid/container.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/container.py 2014-10-17 20:09:04.000000000 +0200
@@ -130,7 +130,7 @@
"""
The GridFlow widget is a flow widget that renders all the widgets it
contains the same width and it arranges them from left to right and top to
- bottom.
+ bottom.
"""
def sizing(self):
return frozenset([FLOW])
@@ -284,7 +284,7 @@
empty.
"""
if not self.contents:
- raise IndexError, "No focus_position, GridFlow is empty"
+ raise IndexError("No focus_position, GridFlow is empty")
return self.contents.focus
def _set_focus_position(self, position):
"""
@@ -296,7 +296,7 @@
if position < 0 or position >= len(self.contents):
raise IndexError
except (TypeError, IndexError):
- raise IndexError, "No GridFlow child widget at position %s" % (position,)
+ raise IndexError("No GridFlow child widget at position %s" % (position,))
self.contents.focus = position
focus_position = property(_get_focus_position, _set_focus_position, doc="""
index of child widget in focus. Raises :exc:`IndexError` if read when
@@ -342,14 +342,18 @@
if self.v_sep:
p.contents.append((divider, p.options()))
c = Columns([], self.h_sep)
+ column_focused = False
pad = Padding(c, self.align)
# extra attribute to reference contents position
pad.first_position = i
p.contents.append((pad, p.options()))
c.contents.append((w, c.options(GIVEN, width_amount)))
- if i == self.focus_position:
+ if ((i == self.focus_position) or
+ (not column_focused and w.selectable())):
c.focus_position = len(c.contents) - 1
+ column_focused = True
+ if i == self.focus_position:
p.focus_position = len(p.contents) - 1
used_space = (sum(x[1][1] for x in c.contents) +
self.h_sep * len(c.contents))
@@ -607,7 +611,7 @@
position -- index of child widget to be made focus
"""
if position != 1:
- raise IndexError, ("Overlay widget focus_position currently "
+ raise IndexError("Overlay widget focus_position currently "
"must always be set to 1, not %s" % (position,))
focus_position = property(_get_focus_position, _set_focus_position,
doc="index of child widget in focus, currently always 1")
@@ -871,10 +875,10 @@
:type part: str
"""
if part not in ('header', 'footer', 'body'):
- raise IndexError, 'Invalid position for Frame: %s' % (part,)
+ raise IndexError('Invalid position for Frame: %s' % (part,))
if (part == 'header' and self._header is None) or (
part == 'footer' and self._footer is None):
- raise IndexError, 'This Frame has no %s' % (part,)
+ raise IndexError('This Frame has no %s' % (part,))
self.focus_part = part
self._invalidate()
@@ -1407,7 +1411,7 @@
empty.
"""
if not self.contents:
- raise IndexError, "No focus_position, Pile is empty"
+ raise IndexError("No focus_position, Pile is empty")
return self.contents.focus
def _set_focus_position(self, position):
"""
@@ -1419,7 +1423,7 @@
if position < 0 or position >= len(self.contents):
raise IndexError
except (TypeError, IndexError):
- raise IndexError, "No Pile child widget at position %s" % (position,)
+ raise IndexError("No Pile child widget at position %s" % (position,))
self.contents.focus = position
focus_position = property(_get_focus_position, _set_focus_position, doc="""
index of child widget in focus. Raises :exc:`IndexError` if read when
@@ -1488,7 +1492,7 @@
l.append(0) # zero-weighted items treated as ('given', 0)
if wtotal == 0:
- raise PileError, "No weighted widgets found for Pile treated as a box widget"
+ raise PileError("No weighted widgets found for Pile treated as a box widget")
if remaining < 0:
remaining = 0
@@ -1957,7 +1961,7 @@
empty.
"""
if not self.widget_list:
- raise IndexError, "No focus_position, Columns is empty"
+ raise IndexError("No focus_position, Columns is empty")
return self.contents.focus
def _set_focus_position(self, position):
"""
@@ -1969,7 +1973,7 @@
if position < 0 or position >= len(self.contents):
raise IndexError
except (TypeError, IndexError):
- raise IndexError, "No Columns child widget at position %s" % (position,)
+ raise IndexError("No Columns child widget at position %s" % (position,))
self.contents.focus = position
focus_position = property(_get_focus_position, _set_focus_position, doc="""
index of child widget in focus. Raises :exc:`IndexError` if read when
diff -Nru urwid-1.2.1/urwid/curses_display.py urwid-1.3.0/urwid/curses_display.py
--- urwid-1.2.1/urwid/curses_display.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/curses_display.py 2014-10-17 20:09:04.000000000 +0200
@@ -102,12 +102,10 @@
self._mouse_tracking_enabled = enable
- def start(self):
+ def _start(self):
"""
Initialize the screen and input mode.
"""
- assert self._started == False
-
self.s = curses.initscr()
self.has_color = curses.has_colors()
if self.has_color:
@@ -126,44 +124,28 @@
curses.meta(1)
curses.halfdelay(10) # use set_input_timeouts to adjust
self.s.keypad(0)
-
+
if not self._signal_keys_set:
self._old_signal_keys = self.tty_signal_keys()
- super(Screen, self).start()
+ super(Screen, self)._start()
-
- def stop(self):
+ def _stop(self):
"""
Restore the screen.
"""
- if self._started == False:
- return
curses.echo()
self._curs_set(1)
try:
curses.endwin()
except _curses.error:
pass # don't block original error with curses error
-
+
if self._old_signal_keys:
self.tty_signal_keys(*self._old_signal_keys)
- super(Screen, self).stop()
+ super(Screen, self)._stop()
-
- def run_wrapper(self,fn):
- """Call fn in fullscreen mode. Return to normal on exit.
-
- This function should be called to wrap your main program loop.
- Exception tracebacks will be displayed in normal mode.
- """
-
- try:
- self.start()
- return fn()
- finally:
- self.stop()
def _setup_colour_pairs(self):
"""
@@ -185,7 +167,7 @@
curses.init_pair(bg * 8 + 7 - fg, fg, bg)
def _curs_set(self,x):
- if self.cursor_state== "fixed" or x == self.cursor_state:
+ if self.cursor_state== "fixed" or x == self.cursor_state:
return
try:
curses.curs_set(x)
@@ -193,12 +175,12 @@
except _curses.error:
self.cursor_state = "fixed"
-
+
def _clear(self):
self.s.clear()
self.s.refresh()
-
-
+
+
def _getch(self, wait_tenths):
if wait_tenths==0:
return self._getch_nodelay()
@@ -208,7 +190,7 @@
curses.halfdelay(wait_tenths)
self.s.nodelay(0)
return self.s.getch()
-
+
def _getch_nodelay(self):
self.s.nodelay(1)
while 1:
@@ -218,17 +200,17 @@
break
except _curses.error:
pass
-
+
return self.s.getch()
- def set_input_timeouts(self, max_wait=None, complete_wait=0.1,
+ def set_input_timeouts(self, max_wait=None, complete_wait=0.1,
resize_wait=0.1):
"""
Set the get_input timeout values. All values have a granularity
of 0.1s, ie. any value between 0.15 and 0.05 will be treated as
0.1 and any value less than 0.05 will be treated as 0. The
maximum timeout value for this module is 25.5 seconds.
-
+
max_wait -- amount of time in seconds to wait for input when
there is no input pending, wait forever if None
complete_wait -- amount of time in seconds to wait when
@@ -295,14 +277,14 @@
keys, raw = self._get_input( self.max_tenths )
# Avoid pegging CPU at 100% when slowly resizing, and work
- # around a bug with some braindead curses implementations that
- # return "no key" between "window resize" commands
+ # around a bug with some braindead curses implementations that
+ # return "no key" between "window resize" commands
if keys==['window resize'] and self.prev_input_resize:
while True:
keys, raw2 = self._get_input(self.resize_tenths)
raw += raw2
if not keys:
- keys, raw2 = self._get_input(
+ keys, raw2 = self._get_input(
self.resize_tenths)
raw += raw2
if keys!=['window resize']:
@@ -310,33 +292,33 @@
if keys[-1:]!=['window resize']:
keys.append('window resize')
-
+
if keys==['window resize']:
self.prev_input_resize = 2
elif self.prev_input_resize == 2 and not keys:
self.prev_input_resize = 1
else:
self.prev_input_resize = 0
-
+
if raw_keys:
return keys, raw
return keys
-
-
+
+
def _get_input(self, wait_tenths):
- # this works around a strange curses bug with window resizing
+ # this works around a strange curses bug with window resizing
# not being reported correctly with repeated calls to this
# function without a doupdate call in between
- curses.doupdate()
-
+ curses.doupdate()
+
key = self._getch(wait_tenths)
resize = False
raw = []
keys = []
-
+
while key >= 0:
raw.append(key)
- if key==KEY_RESIZE:
+ if key==KEY_RESIZE:
resize = True
elif key==KEY_MOUSE:
keys += self._encode_mouse_event()
@@ -345,7 +327,7 @@
key = self._getch_nodelay()
processed = []
-
+
try:
while keys:
run, keys = escape.process_keyqueue(keys, True)
@@ -354,7 +336,7 @@
key = self._getch(self.complete_tenths)
while key >= 0:
raw.append(key)
- if key==KEY_RESIZE:
+ if key==KEY_RESIZE:
resize = True
elif key==KEY_MOUSE:
keys += self._encode_mouse_event()
@@ -369,23 +351,23 @@
processed.append('window resize')
return processed, raw
-
-
+
+
def _encode_mouse_event(self):
# convert to escape sequence
last = next = self.last_bstate
(id,x,y,z,bstate) = curses.getmouse()
-
+
mod = 0
if bstate & curses.BUTTON_SHIFT: mod |= 4
if bstate & curses.BUTTON_ALT: mod |= 8
if bstate & curses.BUTTON_CTRL: mod |= 16
-
+
l = []
def append_button( b ):
b |= mod
l.extend([ 27, ord('['), ord('M'), b+32, x+33, y+33 ])
-
+
if bstate & curses.BUTTON1_PRESSED and last & 1 == 0:
append_button( 0 )
next |= 1
@@ -410,7 +392,7 @@
if bstate & curses.BUTTON4_RELEASED and last & 8:
append_button( 64 + escape.MOUSE_RELEASE_FLAG )
next &= ~ 8
-
+
if bstate & curses.BUTTON1_DOUBLE_CLICKED:
append_button( 0 + escape.MOUSE_MULTIPLE_CLICK_FLAG )
if bstate & curses.BUTTON2_DOUBLE_CLICKED:
@@ -431,7 +413,7 @@
self.last_bstate = next
return l
-
+
def _dbg_instr(self): # messy input string (intended for debugging)
curses.echo()
@@ -440,17 +422,17 @@
str = self.s.getstr()
curses.noecho()
return str
-
+
def _dbg_out(self,str): # messy output function (intended for debugging)
self.s.clrtoeol()
self.s.addstr(str)
self.s.refresh()
self._curs_set(1)
-
+
def _dbg_query(self,question): # messy query (intended for debugging)
self._dbg_out(question)
return self._dbg_instr()
-
+
def _dbg_refresh(self):
self.s.refresh()
@@ -460,7 +442,7 @@
"""Return the terminal dimensions (num columns, num rows)."""
rows,cols = self.s.getmaxyx()
return cols,rows
-
+
def _setattr(self, a):
if a is None:
@@ -502,19 +484,19 @@
def draw_screen(self, (cols, rows), r ):
"""Paint screen with rendered canvas."""
assert self._started
-
+
assert r.rows() == rows, "canvas size and passed size don't match"
-
+
y = -1
for row in r.content():
y += 1
try:
self.s.move( y, 0 )
except _curses.error:
- # terminal shrunk?
+ # terminal shrunk?
# move failed so stop rendering.
return
-
+
first = True
lasta = None
nr = 0
@@ -558,7 +540,7 @@
else:
self._curs_set(0)
self.s.move(0,0)
-
+
self.s.refresh()
self.keep_cache_alive_link = r
@@ -585,7 +567,7 @@
(c+" on light gray",c,'light gray', 'standout'),
])
self.ui.run_wrapper(self.run)
-
+
def run(self):
class FakeRender: pass
r = FakeRender()
@@ -593,12 +575,12 @@
attr = [[],[]]
r.coords = {}
r.cursor = None
-
+
for c in self.l:
t = ""
a = []
for p in c+" on black",c+" on dark blue",c+" on light gray":
-
+
a.append((p,27))
t=t+ (p+27*" ")[:27]
text.append( t )
@@ -624,13 +606,13 @@
t += "'"+k + "' "
a += [(None,1), ('yellow on dark blue',len(k)),
(None,2)]
-
+
text.append(t + ": "+ repr(raw))
attr.append(a)
text = text[-rows:]
attr = attr[-rows:]
-
-
+
+
if '__main__'==__name__:
diff -Nru urwid-1.2.1/urwid/display_common.py urwid-1.3.0/urwid/display_common.py
--- urwid-1.2.1/urwid/display_common.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/display_common.py 2014-10-17 20:09:04.000000000 +0200
@@ -20,9 +20,13 @@
import os
import sys
-import termios
-from urwid.util import int_scale
+try:
+ import termios
+except ImportError:
+ pass # windows
+
+from urwid.util import StoppingContext, int_scale
from urwid import signals
from urwid.compat import B, bytes3
@@ -63,11 +67,11 @@
(0x5c, 0x5c, 0xff), (255, 0, 255), (0, 255, 255), (255, 255, 255)]
_COLOR_VALUES_256 = (_BASIC_COLOR_VALUES +
- [(r, g, b) for r in _CUBE_STEPS_256 for g in _CUBE_STEPS_256
+ [(r, g, b) for r in _CUBE_STEPS_256 for g in _CUBE_STEPS_256
for b in _CUBE_STEPS_256] +
[(gr, gr, gr) for gr in _GRAY_STEPS_256])
_COLOR_VALUES_88 = (_BASIC_COLOR_VALUES +
- [(r, g, b) for r in _CUBE_STEPS_88 for g in _CUBE_STEPS_88
+ [(r, g, b) for r in _CUBE_STEPS_88 for g in _CUBE_STEPS_88
for b in _CUBE_STEPS_88] +
[(gr, gr, gr) for gr in _GRAY_STEPS_88])
@@ -138,10 +142,10 @@
"""
Generate a lookup table for finding the closest item in values.
Lookup returns (index into values)+1
-
+
values -- list of values in ascending order, all < size
size -- size of lookup table and maximum value
-
+
>>> _value_lookup_table([0, 7, 9], 10)
[0, 0, 0, 0, 1, 1, 1, 1, 2, 2]
"""
@@ -177,11 +181,11 @@
for n in range(101)]
-# The functions _gray_num_256() and _gray_num_88() do not include the gray
-# values from the color cube so that the gray steps are an even width.
-# The color cube grays are available by using the rgb functions. Pure
-# white and black are taken from the color cube, since the gray range does
-# not include them, and the basic colors are more likely to have been
+# The functions _gray_num_256() and _gray_num_88() do not include the gray
+# values from the color cube so that the gray steps are an even width.
+# The color cube grays are available by using the rgb functions. Pure
+# white and black are taken from the color cube, since the gray range does
+# not include them, and the basic colors are more likely to have been
# customized by an end-user.
@@ -258,7 +262,7 @@
0..15 -> 'h0'..'h15' basic colors (as high-colors)
16..79 -> '#000'..'#fff' color cube colors
80..87 -> 'g18'..'g90' grays
-
+
>>> _color_desc_88(15)
'h15'
>>> _color_desc_88(16)
@@ -291,7 +295,7 @@
'#000'..'#fff' -> 16..231 color cube colors
'g0'..'g100' -> 16, 232..255, 231 grays and color cube black/white
'g#00'..'g#ff' -> 16, 232...255, 231 gray and color cube black/white
-
+
Returns None if desc is invalid.
>>> _parse_color_256('h142')
@@ -359,9 +363,9 @@
'#000'..'#fff' -> 16..79 color cube colors
'g0'..'g100' -> 16, 80..87, 79 grays and color cube black/white
'g#00'..'g#ff' -> 16, 80...87, 79 gray and color cube black/white
-
+
Returns None if desc is invalid.
-
+
>>> _parse_color_88('h142')
>>> _parse_color_88('h42')
42
@@ -434,7 +438,7 @@
'default' (use the terminal's default foreground),
'black', 'dark red', 'dark green', 'brown', 'dark blue',
'dark magenta', 'dark cyan', 'light gray', 'dark gray',
- 'light red', 'light green', 'yellow', 'light blue',
+ 'light red', 'light green', 'yellow', 'light blue',
'light magenta', 'light cyan', 'white'
High-color example values:
@@ -466,7 +470,7 @@
colors -- the maximum colors available for the specification
- Valid values include: 1, 16, 88 and 256. High-color
+ Valid values include: 1, 16, 88 and 256. High-color
values are only usable with 88 or 256 colors. With
1 color only the foreground settings may be used.
@@ -494,7 +498,7 @@
foreground_number = property(lambda s: s._value & _FG_COLOR_MASK)
background_basic = property(lambda s: s._value & _BG_BASIC_COLOR != 0)
background_high = property(lambda s: s._value & _BG_HIGH_COLOR != 0)
- background_number = property(lambda s: (s._value & _BG_COLOR_MASK)
+ background_number = property(lambda s: (s._value & _BG_COLOR_MASK)
>> _BG_SHIFT)
bold = property(lambda s: s._value & _BOLD != 0)
underline = property(lambda s: s._value & _UNDERLINE != 0)
@@ -552,7 +556,7 @@
# parse and store "settings"/attributes in flags
if flags & _ATTRIBUTES[part]:
raise AttrSpecError(("Setting %s specified more than" +
- "once in foreground (%s)") % (repr(part),
+ "once in foreground (%s)") % (repr(part),
repr(foreground)))
flags |= _ATTRIBUTES[part]
continue
@@ -591,7 +595,7 @@
if self._value & _HIGH_88_COLOR:
return _color_desc_88(self.background_number)
return _color_desc_256(self.background_number)
-
+
def _set_background(self, background):
flags = 0
if background in ('', 'default'):
@@ -617,7 +621,7 @@
Return (fg_red, fg_green, fg_blue, bg_red, bg_green, bg_blue) color
components. Each component is in the range 0-255. Values are taken
from the XTerm defaults and may not exactly match the user's terminal.
-
+
If the foreground or background is 'default' then all their compenents
will be returned as None.
@@ -649,8 +653,8 @@
super(RealTerminal,self).__init__()
self._signal_keys_set = False
self._old_signal_keys = None
-
- def tty_signal_keys(self, intr=None, quit=None, start=None,
+
+ def tty_signal_keys(self, intr=None, quit=None, start=None,
stop=None, susp=None, fileno=None):
"""
Read and/or set the tty's signal character settings.
@@ -675,25 +679,25 @@
skeys = (sattr[termios.VINTR], sattr[termios.VQUIT],
sattr[termios.VSTART], sattr[termios.VSTOP],
sattr[termios.VSUSP])
-
+
if intr == 'undefined': intr = 0
if quit == 'undefined': quit = 0
if start == 'undefined': start = 0
if stop == 'undefined': stop = 0
if susp == 'undefined': susp = 0
-
+
if intr is not None: tattr[6][termios.VINTR] = intr
if quit is not None: tattr[6][termios.VQUIT] = quit
if start is not None: tattr[6][termios.VSTART] = start
if stop is not None: tattr[6][termios.VSTOP] = stop
if susp is not None: tattr[6][termios.VSUSP] = susp
-
+
if intr is not None or quit is not None or \
start is not None or stop is not None or \
susp is not None:
termios.tcsetattr(fileno, termios.TCSADRAIN, tattr)
self._signal_keys_set = True
-
+
return skeys
@@ -714,12 +718,44 @@
started = property(lambda self: self._started)
- def start(self):
+ def start(self, *args, **kwargs):
+ """Set up the screen. If the screen has already been started, does
+ nothing.
+
+ May be used as a context manager, in which case :meth:`stop` will
+ automatically be called at the end of the block:
+
+ with screen.start():
+ ...
+
+ You shouldn't override this method in a subclass; instead, override
+ :meth:`_start`.
+ """
+ if not self._started:
+ self._start(*args, **kwargs)
self._started = True
+ return StoppingContext(self)
+
+ def _start(self):
+ pass
def stop(self):
+ if self._started:
+ self._stop()
self._started = False
+ def _stop(self):
+ pass
+
+ def run_wrapper(self, fn, *args, **kwargs):
+ """Start the screen, call a function, then stop the screen. Extra
+ arguments are passed to `start`.
+
+ Deprecated in favor of calling `start` as a context manager.
+ """
+ with self.start(*args, **kwargs):
+ return fn()
+
def register_palette(self, palette):
"""Register a set of palette entries.
@@ -746,7 +782,7 @@
raise ScreenError("Invalid register_palette entry: %s" %
repr(item))
name, like_name = item
- if not self._palette.has_key(like_name):
+ if like_name not in self._palette:
raise ScreenError("palette entry '%s' doesn't exist"%like_name)
self._palette[name] = self._palette[like_name]
@@ -829,6 +865,8 @@
def large_h(desc):
if not desc.startswith('h'):
return False
+ if ',' in desc:
+ desc = desc.split(',',1)[0]
num = int(desc[1:], 10)
return num > 15
if large_h(foreground_high) or large_h(background_high):
diff -Nru urwid-1.2.1/urwid/escape.py urwid-1.3.0/urwid/escape.py
--- urwid-1.2.1/urwid/escape.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/escape.py 2014-10-17 20:09:04.000000000 +0200
@@ -63,7 +63,7 @@
def escape_modifier( digit ):
mode = ord(digit) - ord("1")
return "shift "*(mode&1) + "meta "*((mode&2)//2) + "ctrl "*((mode&4)//4)
-
+
input_sequences = [
('[A','up'),('[B','down'),('[C','right'),('[D','left'),
@@ -74,7 +74,7 @@
('[7~','home'),('[8~','end'),
('[[A','f1'),('[[B','f2'),('[[C','f3'),('[[D','f4'),('[[E','f5'),
-
+
('[11~','f1'),('[12~','f2'),('[13~','f3'),('[14~','f4'),
('[15~','f5'),('[17~','f6'),('[18~','f7'),('[19~','f8'),
('[20~','f9'),('[21~','f10'),('[23~','f11'),('[24~','f12'),
@@ -102,7 +102,7 @@
] + [
# modified cursor keys + home, end, 5 -- [#X and [1;#X forms
(prefix+digit+letter, escape_modifier(digit) + key)
- for prefix in "[","[1;"
+ for prefix in ("[", "[1;")
for digit in "12345678"
for letter,key in zip("ABCDEFGH",
('up','down','right','left','5','end','5','home'))
@@ -111,7 +111,7 @@
("O"+digit+letter, escape_modifier(digit) + key)
for digit in "12345678"
for letter,key in zip("PQRS",('f1','f2','f3','f4'))
-] + [
+] + [
# modified F1-F13 keys -- [XX;#~ form
("["+str(num)+";"+digit+"~", escape_modifier(digit) + key)
for digit in "12345678"
@@ -133,29 +133,29 @@
for s, result in sequences:
assert type(result) != dict
self.add(self.data, s, result)
-
+
def add(self, root, s, result):
assert type(root) == dict, "trie conflict detected"
assert len(s) > 0, "trie conflict detected"
-
- if root.has_key(ord(s[0])):
+
+ if ord(s[0]) in root:
return self.add(root[ord(s[0])], s[1:], result)
if len(s)>1:
d = {}
root[ord(s[0])] = d
return self.add(d, s[1:], result)
root[ord(s)] = result
-
+
def get(self, keys, more_available):
result = self.get_recurse(self.data, keys, more_available)
if not result:
result = self.read_cursor_position(keys, more_available)
return result
-
+
def get_recurse(self, root, keys, more_available):
if type(root) != dict:
if root == "mouse":
- return self.read_mouse_info(keys,
+ return self.read_mouse_info(keys,
more_available)
return (root, keys)
if not keys:
@@ -163,19 +163,19 @@
if more_available:
raise MoreInputRequired()
return None
- if not root.has_key(keys[0]):
+ if keys[0] not in root:
return None
return self.get_recurse(root[keys[0]], keys[1:], more_available)
-
+
def read_mouse_info(self, keys, more_available):
if len(keys) < 3:
if more_available:
raise MoreInputRequired()
return None
-
+
b = keys[0] - 32
x, y = (keys[1] - 33)%256, (keys[2] - 33)%256 # supports 0-255
-
+
prefix = ""
if b & 4: prefix = prefix + "shift "
if b & 8: prefix = prefix + "meta "
@@ -186,7 +186,7 @@
# 0->1, 1->2, 2->3, 64->4, 65->5
button = ((b&64)/64*3) + (b & 3) + 1
- if b & 3 == 3:
+ if b & 3 == 3:
action = "release"
button = 0
elif b & MOUSE_RELEASE_FLAG:
@@ -199,7 +199,7 @@
action = "press"
return ( (prefix + "mouse " + action, button, x, y), keys[3:] )
-
+
def read_cursor_position(self, keys, more_available):
"""
Interpret cursor position information being sent by the
@@ -252,8 +252,8 @@
# This is added to button value to signal mouse release by curses_display
-# and raw_display when we know which button was released. NON-STANDARD
-MOUSE_RELEASE_FLAG = 2048
+# and raw_display when we know which button was released. NON-STANDARD
+MOUSE_RELEASE_FLAG = 2048
# This 2-bit mask is used to check if the mouse release from curses or gpm
# is a double or triple release. 00 means single click, 01 double,
@@ -308,26 +308,26 @@
def process_keyqueue(codes, more_available):
"""
codes -- list of key codes
- more_available -- if True then raise MoreInputRequired when in the
- middle of a character sequence (escape/utf8/wide) and caller
+ more_available -- if True then raise MoreInputRequired when in the
+ middle of a character sequence (escape/utf8/wide) and caller
will attempt to send more key codes on the next call.
-
+
returns (list of input, list of remaining key codes).
"""
code = codes[0]
if code >= 32 and code <= 126:
key = chr(code)
return [key], codes[1:]
- if _keyconv.has_key(code):
+ if code in _keyconv:
return [_keyconv[code]], codes[1:]
if code >0 and code <27:
return ["ctrl %s" % chr(ord('a')+code-1)], codes[1:]
if code >27 and code <32:
return ["ctrl %s" % chr(ord('A')+code-1)], codes[1:]
-
+
em = str_util.get_byte_encoding()
-
- if (em == 'wide' and code < 256 and
+
+ if (em == 'wide' and code < 256 and
within_double_byte(chr(code),0,0)):
if not codes[1:]:
if more_available:
@@ -363,7 +363,7 @@
return [s.decode("utf-8")], codes[need_more+1:]
except UnicodeDecodeError:
return ["<%d>"%code], codes[1:]
-
+
if code >127 and code <256:
key = chr(code)
return [key], codes[1:]
@@ -371,19 +371,19 @@
return ["<%d>"%code], codes[1:]
result = input_trie.get(codes[1:], more_available)
-
+
if result is not None:
result, remaining_codes = result
return [result], remaining_codes
-
+
if codes[1:]:
# Meta keys -- ESC+Key form
- run, remaining_codes = process_keyqueue(codes[1:],
+ run, remaining_codes = process_keyqueue(codes[1:],
more_available)
if run[0] == "esc" or run[0].find("meta ") >= 0:
return ['esc']+run, remaining_codes
return ['meta '+run[0]]+run[1:], remaining_codes
-
+
return ['esc'], codes[1:]
diff -Nru urwid-1.2.1/urwid/font.py urwid-1.3.0/urwid/font.py
--- urwid-1.2.1/urwid/font.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/font.py 2014-10-17 20:09:04.000000000 +0200
@@ -65,11 +65,11 @@
j += 1
assert y + fill == end_col - start_col, \
repr((y, fill, end_col))
-
+
segment = l[jl[k]:j]
if not SAFE_ASCII_DEC_SPECIAL_RE.match(segment):
utf8_required = True
-
+
out.append(segment + " " * fill)
jl[k] = j
@@ -98,7 +98,7 @@
self.utf8_required = False
for gdata in self.data:
self.add_glyphs(gdata)
-
+
def add_glyphs(self, gdata):
d, utf8_required = separate_glyphs(gdata, self.height)
@@ -111,10 +111,10 @@
return "".join(l)
def char_width(self, c):
- if self.char.has_key(c):
+ if c in self.char:
return self.char[c][0]
return 0
-
+
def char_data(self, c):
return self.char[c][1]
@@ -128,13 +128,13 @@
t, cs = apply_target_encoding(d)
tl.append(t)
csl.append(cs)
- canv = TextCanvas(tl, None, csl, maxcol=width,
+ canv = TextCanvas(tl, None, csl, maxcol=width,
check_width=False)
self.canvas[c] = canv
return canv
-
-
+
+
#safe_palette = u"┘┐┌└┼─├┤┴┬│"
#more_palette = u"═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬○"
#block_palette = u"▄#█#▀#▌#▐#▖#▗#▘#▙#▚#▛#▜#▝#▞#▟"
@@ -150,7 +150,7 @@
""", ur"""
"###$$$%%%'*++,--.///:;==???[[\\\]]^__`
" ┼┼┌┼┐O /' /.. _┌─┐┌ \ ┐^ `
- ┼┼└┼┐ / * ┼ ─ / ., _ ┌┘│ \ │
+ ┼┼└┼┐ / * ┼ ─ / ., _ ┌┘│ \ │
└┼┘/ O , ./ . └ \ ┘ ──
"""]
add_font("Thin 3x3",Thin3x3Font)
@@ -169,57 +169,57 @@
height = 4
data = [u"""
00000111112222233333444445555566666777778888899999 !!
-▄▀▀▄ ▄█ ▄▀▀▄ ▄▀▀▄ ▄ █ █▀▀▀ ▄▀▀ ▀▀▀█ ▄▀▀▄ ▄▀▀▄ █
-█ █ █ ▄▀ ▄▀ █▄▄█ █▄▄ █▄▄ ▐▌ ▀▄▄▀ ▀▄▄█ █
-█ █ █ ▄▀ ▄ █ █ █ █ █ █ █ █ █ ▀
- ▀▀ ▀▀▀ ▀▀▀▀ ▀▀ ▀ ▀▀▀ ▀▀ ▀ ▀▀ ▀▀ ▀
+▄▀▀▄ ▄█ ▄▀▀▄ ▄▀▀▄ ▄ █ █▀▀▀ ▄▀▀ ▀▀▀█ ▄▀▀▄ ▄▀▀▄ █
+█ █ █ ▄▀ ▄▀ █▄▄█ █▄▄ █▄▄ ▐▌ ▀▄▄▀ ▀▄▄█ █
+█ █ █ ▄▀ ▄ █ █ █ █ █ █ █ █ █ ▀
+ ▀▀ ▀▀▀ ▀▀▀▀ ▀▀ ▀ ▀▀▀ ▀▀ ▀ ▀▀ ▀▀ ▀
""", u'''
"""######$$$$$$%%%%%&&&&&((()))******++++++,,,-----..////:::;;
-█▐▌ █ █ ▄▀█▀▄ ▐▌▐▌ ▄▀▄ █ █ ▄ ▄ ▄ ▐▌
- ▀█▀█▀ ▀▄█▄ █ ▀▄▀ ▐▌ ▐▌ ▄▄█▄▄ ▄▄█▄▄ ▄▄▄▄ █ ▀ ▀
- ▀█▀█▀ ▄ █ █ ▐▌▄ █ ▀▄▌▐▌ ▐▌ ▄▀▄ █ ▐▌ ▀ ▄▀
- ▀ ▀ ▀▀▀ ▀ ▀ ▀▀ ▀ ▀ ▄▀ ▀ ▀
+█▐▌ █ █ ▄▀█▀▄ ▐▌▐▌ ▄▀▄ █ █ ▄ ▄ ▄ ▐▌
+ ▀█▀█▀ ▀▄█▄ █ ▀▄▀ ▐▌ ▐▌ ▄▄█▄▄ ▄▄█▄▄ ▄▄▄▄ █ ▀ ▀
+ ▀█▀█▀ ▄ █ █ ▐▌▄ █ ▀▄▌▐▌ ▐▌ ▄▀▄ █ ▐▌ ▀ ▄▀
+ ▀ ▀ ▀▀▀ ▀ ▀ ▀▀ ▀ ▀ ▄▀ ▀ ▀
''', ur"""
<<<<<=====>>>>>?????@@@@@@[[[[\\\\]]]]^^^^____```{{{{||}}}}~~~~''´´´
- ▄▀ ▀▄ ▄▀▀▄ ▄▀▀▀▄ █▀▀ ▐▌ ▀▀█ ▄▀▄ ▀▄ ▄▀ █ ▀▄ ▄ █ ▄▀
-▄▀ ▀▀▀▀ ▀▄ ▄▀ █ █▀█ █ █ █ ▄▀ █ ▀▄ ▐▐▌▌
- ▀▄ ▀▀▀▀ ▄▀ ▀ █ ▀▀▀ █ ▐▌ █ █ █ █ ▀
- ▀ ▀ ▀ ▀▀▀ ▀▀▀ ▀ ▀▀▀ ▀▀▀▀ ▀ ▀ ▀
+ ▄▀ ▀▄ ▄▀▀▄ ▄▀▀▀▄ █▀▀ ▐▌ ▀▀█ ▄▀▄ ▀▄ ▄▀ █ ▀▄ ▄ █ ▄▀
+▄▀ ▀▀▀▀ ▀▄ ▄▀ █ █▀█ █ █ █ ▄▀ █ ▀▄ ▐▐▌▌
+ ▀▄ ▀▀▀▀ ▄▀ ▀ █ ▀▀▀ █ ▐▌ █ █ █ █ ▀
+ ▀ ▀ ▀ ▀▀▀ ▀▀▀ ▀ ▀▀▀ ▀▀▀▀ ▀ ▀ ▀
""", u'''
AAAAABBBBBCCCCCDDDDDEEEEEFFFFFGGGGGHHHHHIIJJJJJKKKKK
-▄▀▀▄ █▀▀▄ ▄▀▀▄ █▀▀▄ █▀▀▀ █▀▀▀ ▄▀▀▄ █ █ █ █ █ █
-█▄▄█ █▄▄▀ █ █ █ █▄▄ █▄▄ █ █▄▄█ █ █ █▄▀
-█ █ █ █ █ ▄ █ █ █ █ █ ▀█ █ █ █ ▄ █ █ ▀▄
-▀ ▀ ▀▀▀ ▀▀ ▀▀▀ ▀▀▀▀ ▀ ▀▀ ▀ ▀ ▀ ▀▀ ▀ ▀
+▄▀▀▄ █▀▀▄ ▄▀▀▄ █▀▀▄ █▀▀▀ █▀▀▀ ▄▀▀▄ █ █ █ █ █ █
+█▄▄█ █▄▄▀ █ █ █ █▄▄ █▄▄ █ █▄▄█ █ █ █▄▀
+█ █ █ █ █ ▄ █ █ █ █ █ ▀█ █ █ █ ▄ █ █ ▀▄
+▀ ▀ ▀▀▀ ▀▀ ▀▀▀ ▀▀▀▀ ▀ ▀▀ ▀ ▀ ▀ ▀▀ ▀ ▀
''', u'''
LLLLLMMMMMMNNNNNOOOOOPPPPPQQQQQRRRRRSSSSSTTTTT
█ █▄ ▄█ ██ █ ▄▀▀▄ █▀▀▄ ▄▀▀▄ █▀▀▄ ▄▀▀▄ ▀▀█▀▀
-█ █ ▀ █ █▐▌█ █ █ █▄▄▀ █ █ █▄▄▀ ▀▄▄ █
+█ █ ▀ █ █▐▌█ █ █ █▄▄▀ █ █ █▄▄▀ ▀▄▄ █
█ █ █ █ ██ █ █ █ █ ▌█ █ █ ▄ █ █
▀▀▀▀ ▀ ▀ ▀ ▀ ▀▀ ▀ ▀▀▌ ▀ ▀ ▀▀ ▀
''', u'''
UUUUUVVVVVVWWWWWWXXXXXXYYYYYYZZZZZ
-█ █ █ █ █ █ █ █ █ █ ▀▀▀█
-█ █ ▐▌ ▐▌ █ ▄ █ ▀▄▀ ▀▄▀ ▄▀
-█ █ █ █ ▐▌█▐▌ ▄▀ ▀▄ █ █
- ▀▀ ▀ ▀ ▀ ▀ ▀ ▀ ▀▀▀▀
+█ █ █ █ █ █ █ █ █ █ ▀▀▀█
+█ █ ▐▌ ▐▌ █ ▄ █ ▀▄▀ ▀▄▀ ▄▀
+█ █ █ █ ▐▌█▐▌ ▄▀ ▀▄ █ █
+ ▀▀ ▀ ▀ ▀ ▀ ▀ ▀ ▀▀▀▀
''', u'''
aaaaabbbbbcccccdddddeeeeeffffggggghhhhhiijjjjkkkkk
█ █ ▄▀▀ █ ▄ ▄ █
- ▀▀▄ █▀▀▄ ▄▀▀▄ ▄▀▀█ ▄▀▀▄ ▀█▀ ▄▀▀▄ █▀▀▄ ▄ ▄ █ ▄▀
-▄▀▀█ █ █ █ ▄ █ █ █▀▀ █ ▀▄▄█ █ █ █ █ █▀▄
- ▀▀▀ ▀▀▀ ▀▀ ▀▀▀ ▀▀ ▀ ▄▄▀ ▀ ▀ ▀ ▄▄▀ ▀ ▀
+ ▀▀▄ █▀▀▄ ▄▀▀▄ ▄▀▀█ ▄▀▀▄ ▀█▀ ▄▀▀▄ █▀▀▄ ▄ ▄ █ ▄▀
+▄▀▀█ █ █ █ ▄ █ █ █▀▀ █ ▀▄▄█ █ █ █ █ █▀▄
+ ▀▀▀ ▀▀▀ ▀▀ ▀▀▀ ▀▀ ▀ ▄▄▀ ▀ ▀ ▀ ▄▄▀ ▀ ▀
''', u'''
llmmmmmmnnnnnooooopppppqqqqqrrrrssssstttt
-█ █
-█ █▀▄▀▄ █▀▀▄ ▄▀▀▄ █▀▀▄ ▄▀▀█ █▀▀ ▄▀▀▀ ▀█▀
+█ █
+█ █▀▄▀▄ █▀▀▄ ▄▀▀▄ █▀▀▄ ▄▀▀█ █▀▀ ▄▀▀▀ ▀█▀
█ █ █ █ █ █ █ █ █ █ █ █ █ ▀▀▄ █
▀ ▀ ▀ ▀ ▀ ▀▀ █▀▀ ▀▀█ ▀ ▀▀▀ ▀
''', u'''
uuuuuvvvvvwwwwwwxxxxxxyyyyyzzzzz
-
+
█ █ █ █ █ ▄ █ ▀▄ ▄▀ █ █ ▀▀█▀
-█ █ ▐▌▐▌ ▐▌█▐▌ ▄▀▄ ▀▄▄█ ▄▀
+█ █ ▐▌▐▌ ▐▌█▐▌ ▄▀▄ ▀▄▄█ ▄▀
▀▀ ▀▀ ▀ ▀ ▀ ▀ ▄▄▀ ▀▀▀▀
''']
add_font("Half Block 5x4",HalfBlock5x4Font)
@@ -253,34 +253,34 @@
data = [u"""
000000111111222222333333444444555555666666777777888888999999''
┌───┐ ┐ ┌───┐ ┌───┐ ┐ ┌─── ┌─── ┌───┐ ┌───┐ ┌───┐ │
-│ │ │ │ │ ┌ │ │ │ │ │ │ │ │
-│ / │ │ ┌───┘ ─┤ └──┼─ └───┐ ├───┐ ┼ ├───┤ └───┤
-│ │ │ │ │ │ │ │ │ │ │ │ │
-└───┘ ┴ └─── └───┘ ┴ ───┘ └───┘ ┴ └───┘ ───┘
+│ │ │ │ │ ┌ │ │ │ │ │ │ │ │
+│ / │ │ ┌───┘ ─┤ └──┼─ └───┐ ├───┐ ┼ ├───┤ └───┤
+│ │ │ │ │ │ │ │ │ │ │ │ │
+└───┘ ┴ └─── └───┘ ┴ ───┘ └───┘ ┴ └───┘ ───┘
""", ur'''
!! """######$$$$$$%%%%%%&&&&&&((()))******++++++
-│ ││ ┌ ┌ ┌─┼─┐ ┌┐ / ┌─┐ / \
+│ ││ ┌ ┌ ┌─┼─┐ ┌┐ / ┌─┐ / \
│ ─┼─┼─ │ │ └┘ / │ │ │ │ \ / │
-│ │ │ └─┼─┐ / ┌─\┘ │ │ ──X── ──┼──
+│ │ │ └─┼─┐ / ┌─\┘ │ │ ──X── ──┼──
│ ─┼─┼─ │ │ / ┌┐ │ \, │ │ / \ │
-. ┘ ┘ └─┼─┘ / └┘ └───\ \ /
+. ┘ ┘ └─┼─┘ / └┘ └───\ \ /
''', ur"""
,,-----..//////::;;<<<<=====>>>>??????@@@@@@
/ ┌───┐ ┌───┐
/ . . / ──── \ │ │┌──┤
- ──── / / \ ┌─┘ ││ │
+ ──── / / \ ┌─┘ ││ │
/ . , \ ──── / │ │└──┘
, . / \ / . └───┘
""", ur"""
[[\\\\\\]]^^^____``{{||}}~~~~~~
-┌ \ ┐ /\ \ ┌ │ ┐
+┌ \ ┐ /\ \ ┌ │ ┐
│ \ │ │ │ │ ┌─┐
│ \ │ ┤ │ ├ └─┘
-│ \ │ │ │ │
-└ \ ┘ ──── └ │ ┘
+│ \ │ │ │ │
+└ \ ┘ ──── └ │ ┘
""", u"""
AAAAAABBBBBBCCCCCCDDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIIJJJJJJ
@@ -300,15 +300,15 @@
└
""", u"""
TTTTTTUUUUUUVVVVVVWWWWWWXXXXXXYYYYYYZZZZZZ
-┌─┬─┐ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┌───┐
- │ │ │ │ │ │ │ └┐ ┌┘ │ │ ┌─┘
- │ │ │ │ │ │ │ │ ├─┤ └─┬─┘ ┌┘
- │ │ │ └┐ ┌┘ │ │ │ ┌┘ └┐ │ ┌┘
- ┴ └───┘ └─┘ └─┴─┘ ┴ ┴ ┴ └───┘
-
+┌─┬─┐ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┌───┐
+ │ │ │ │ │ │ │ └┐ ┌┘ │ │ ┌─┘
+ │ │ │ │ │ │ │ │ ├─┤ └─┬─┘ ┌┘
+ │ │ │ └┐ ┌┘ │ │ │ ┌┘ └┐ │ ┌┘
+ ┴ └───┘ └─┘ └─┴─┘ ┴ ┴ ┴ └───┘
+
""", u"""
aaaaaabbbbbbccccccddddddeeeeeefffgggggghhhhhhiijjj
- ┌─┐
+ ┌─┐
│ │ │ │ . .
┌───┐ ├───┐ ┌───┐ ┌───┤ ┌───┐ ┼ ┌───┐ ├───┐ ┐ ┐
┌───┤ │ │ │ │ │ ├───┘ │ │ │ │ │ │ │
@@ -316,16 +316,16 @@
└───┘ ─┘
""", u"""
kkkkkkllmmmmmmnnnnnnooooooppppppqqqqqqrrrrrssssss
-
-│ │
+
+│ │
│ ┌─ │ ┬─┬─┐ ┬───┐ ┌───┐ ┌───┐ ┌───┐ ┬──┐ ┌───┐
├─┴┐ │ │ │ │ │ │ │ │ │ │ │ │ │ └───┐
┴ └─ └ ┴ ┴ ┴ ┴ └───┘ ├───┘ └───┤ ┴ └───┘
- │ │
+ │ │
""", u"""
ttttuuuuuuvvvvvvwwwwwwxxxxxxyyyyyyzzzzzz
-
- │
+
+ │
─┼─ ┬ ┬ ┬ ┬ ┬ ┬ ─┐ ┌─ ┬ ┬ ────┬
│ │ │ └┐ ┌┘ │ │ │ ├─┤ │ │ ┌───┘
└─ └───┴ └─┘ └─┴─┘ ─┘ └─ └───┤ ┴────
@@ -340,92 +340,92 @@
0000000111111122222223333333444444455555556666666777777788888889999999'''
▄███▄ ▐█▌ ▄███▄ ▄███▄ █▌ ▐█████▌ ▄███▄ ▐█████▌ ▄███▄ ▄███▄ ▐█
▐█ █▌ ▀█▌ ▐█ █▌▐█ █▌▐█ █▌ ▐█ ▐█ ▐█ ▐█ █▌▐█ █▌▐█
-▐█ ▐ █▌ █▌ █▌ ▐██ ▐█████▌▐████▄ ▐████▄ █▌ █████ ▀████▌
-▐█ ▌ █▌ █▌ ▄█▀ █▌ █▌ █▌▐█ █▌ ▐█ ▐█ █▌ █▌
-▐█ █▌ █▌ ▄█▀ ▐█ █▌ █▌ █▌▐█ █▌ █▌ ▐█ █▌ █▌
- ▀███▀ ███▌ ▐█████▌ ▀███▀ █▌ ▐████▀ ▀███▀ ▐█ ▀███▀ ▀███▀
+▐█ ▐ █▌ █▌ █▌ ▐██ ▐█████▌▐████▄ ▐████▄ █▌ █████ ▀████▌
+▐█ ▌ █▌ █▌ ▄█▀ █▌ █▌ █▌▐█ █▌ ▐█ ▐█ █▌ █▌
+▐█ █▌ █▌ ▄█▀ ▐█ █▌ █▌ █▌▐█ █▌ █▌ ▐█ █▌ █▌
+ ▀███▀ ███▌ ▐█████▌ ▀███▀ █▌ ▐████▀ ▀███▀ ▐█ ▀███▀ ▀███▀
""", u'''
!!! """""#######$$$$$$$%%%%%%%&&&&&&&(((())))*******++++++
-▐█ ▐█ █▌ ▐█ █▌ █ ▄ █▌ ▄█▄ █▌▐█ ▄▄ ▄▄
+▐█ ▐█ █▌ ▐█ █▌ █ ▄ █▌ ▄█▄ █▌▐█ ▄▄ ▄▄
▐█ ▐█ █▌▐█████▌ ▄███▄ ▐█▌▐█ ▐█ █▌ ▐█ █▌ ▀█▄█▀ ▐█
▐█ ▐█ █▌ ▐█▄█▄▄ ▀ █▌ ███ █▌ ▐█ ▐█████▌ ████▌
-▐█ ▐█████▌ ▀▀█▀█▌ ▐█ ▄ ███▌▄ █▌ ▐█ ▄█▀█▄ ▐█
- ▐█ █▌ ▀███▀ █▌▐█▌▐█ █▌ ▐█ █▌ ▀▀ ▀▀
-▐█ █ ▐█ ▀ ▀██▀█▌ █▌▐█
-
+▐█ ▐█████▌ ▀▀█▀█▌ ▐█ ▄ ███▌▄ █▌ ▐█ ▄█▀█▄ ▐█
+ ▐█ █▌ ▀███▀ █▌▐█▌▐█ █▌ ▐█ █▌ ▀▀ ▀▀
+▐█ █ ▐█ ▀ ▀██▀█▌ █▌▐█
+
''', u"""
,,,------.../////:::;;;<<<<<<<======>>>>>>>???????@@@@@@@
- █▌ ▄█▌ ▐█▄ ▄███▄ ▄███▄
- ▐█ ▐█ ▐█ ▄█▀ ▐████▌ ▀█▄ ▐█ █▌▐█ ▄▄█▌
+ █▌ ▄█▌ ▐█▄ ▄███▄ ▄███▄
+ ▐█ ▐█ ▐█ ▄█▀ ▐████▌ ▀█▄ ▐█ █▌▐█ ▄▄█▌
▐████▌ █▌ ▐██ ██▌ █▌ ▐█▐█▀█▌
▐█ ▐█ ▐█ ▀█▄ ▐████▌ ▄█▀ █▌ ▐█▐█▄█▌
- █▌ ▀ ▀█▌ ▐█▀ ▐█ ▀▀▀
-▐█ ▐█ ▐█ █▌ ▀███▀
-▀
+ █▌ ▀ ▀█▌ ▐█▀ ▐█ ▀▀▀
+▐█ ▐█ ▐█ █▌ ▀███▀
+▀
""", ur"""
[[[[\\\\\]]]]^^^^^^^_____```{{{{{|||}}}}}~~~~~~~´´´
-▐██▌▐█ ▐██▌ ▐█▌ ▐█ █▌▐█ ▐█ █▌
-▐█ █▌ █▌ ▐█ █▌ █▌ █▌ ▐█ ▐█ ▄▄ ▐█
+▐██▌▐█ ▐██▌ ▐█▌ ▐█ █▌▐█ ▐█ █▌
+▐█ █▌ █▌ ▐█ █▌ █▌ █▌ ▐█ ▐█ ▄▄ ▐█
▐█ ▐█ █▌▐█ █▌ ▄█▌ ▐█ ▐█▄ ▐▀▀█▄▄▌
▐█ █▌ █▌ ▀█▌ ▐█ ▐█▀ ▀▀
-▐█ ▐█ █▌ █▌ ▐█ ▐█
-▐██▌ █▌▐██▌ █████ █▌▐█ ▐█
-
+▐█ ▐█ █▌ █▌ ▐█ ▐█
+▐██▌ █▌▐██▌ █████ █▌▐█ ▐█
+
""", u"""
AAAAAAABBBBBBBCCCCCCCDDDDDDDEEEEEEEFFFFFFFGGGGGGGHHHHHHHIIIIJJJJJJJ
- ▄███▄ ▐████▄ ▄███▄ ▐████▄ ▐█████▌▐█████▌ ▄███▄ ▐█ █▌ ██▌ █▌
-▐█ █▌▐█ █▌▐█ ▐█ █▌▐█ ▐█ ▐█ ▐█ █▌ ▐█ █▌
+ ▄███▄ ▐████▄ ▄███▄ ▐████▄ ▐█████▌▐█████▌ ▄███▄ ▐█ █▌ ██▌ █▌
+▐█ █▌▐█ █▌▐█ ▐█ █▌▐█ ▐█ ▐█ ▐█ █▌ ▐█ █▌
▐█████▌▐█████ ▐█ ▐█ █▌▐████ ▐████ ▐█ ▐█████▌ ▐█ █▌
▐█ █▌▐█ █▌▐█ ▐█ █▌▐█ ▐█ ▐█ ██▌▐█ █▌ ▐█ █▌
▐█ █▌▐█ █▌▐█ ▐█ █▌▐█ ▐█ ▐█ █▌▐█ █▌ ▐█ ▐█ █▌
-▐█ █▌▐████▀ ▀███▀ ▐████▀ ▐█████▌▐█ ▀███▀ ▐█ █▌ ██▌ ▀███▀
-
+▐█ █▌▐████▀ ▀███▀ ▐████▀ ▐█████▌▐█ ▀███▀ ▐█ █▌ ██▌ ▀███▀
+
""", u"""
KKKKKKKLLLLLLLMMMMMMMMNNNNNNNOOOOOOOPPPPPPPQQQQQQQRRRRRRRSSSSSSS
-▐█ █▌▐█ ▄█▌▐█▄ ▐██ █▌ ▄███▄ ▐████▄ ▄███▄ ▐████▄ ▄███▄
-▐█ █▌ ▐█ ▐█ ▐▌ █▌▐██▌ █▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌▐█
-▐█▄█▌ ▐█ ▐█ ▐▌ █▌▐█▐█ █▌▐█ █▌▐████▀ ▐█ █▌▐█████ ▀███▄
+▐█ █▌▐█ ▄█▌▐█▄ ▐██ █▌ ▄███▄ ▐████▄ ▄███▄ ▐████▄ ▄███▄
+▐█ █▌ ▐█ ▐█ ▐▌ █▌▐██▌ █▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌▐█
+▐█▄█▌ ▐█ ▐█ ▐▌ █▌▐█▐█ █▌▐█ █▌▐████▀ ▐█ █▌▐█████ ▀███▄
▐█▀█▌ ▐█ ▐█ █▌▐█ █▌█▌▐█ █▌▐█ ▐█ █▌▐█ █▌ █▌
▐█ █▌ ▐█ ▐█ █▌▐█ ▐██▌▐█ █▌▐█ ▐█ █▌█▌▐█ █▌ █▌
-▐█ █▌▐█████▌▐█ █▌▐█ ██▌ ▀███▀ ▐█ ▀███▀ ▐█ █▌ ▀███▀
- ▀▀
+▐█ █▌▐█████▌▐█ █▌▐█ ██▌ ▀███▀ ▐█ ▀███▀ ▐█ █▌ ▀███▀
+ ▀▀
""", u"""
TTTTTTTUUUUUUUVVVVVVVWWWWWWWWXXXXXXXYYYYYYYZZZZZZZ
- █████▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌ █▌ █▌▐█████▌
- █▌ ▐█ █▌ █▌ ▐█ ▐█ █▌ ▐█ █▌ ▐█ ▐█ █▌
- █▌ ▐█ █▌ ▐█ █▌ ▐█ █▌ ▐█▌ ▐██ █▌
+ █████▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌ █▌ █▌▐█████▌
+ █▌ ▐█ █▌ █▌ ▐█ ▐█ █▌ ▐█ █▌ ▐█ ▐█ █▌
+ █▌ ▐█ █▌ ▐█ █▌ ▐█ █▌ ▐█▌ ▐██ █▌
█▌ ▐█ █▌ ███ ▐█ ▐▌ █▌ ███ █▌ █▌
█▌ ▐█ █▌ ▐█▌ ▐█ ▐▌ █▌ █▌ ▐█ █▌ █▌
- █▌ ▀███▀ █ ▀█▌▐█▀ ▐█ █▌ █▌ ▐█████▌
-
+ █▌ ▀███▀ █ ▀█▌▐█▀ ▐█ █▌ █▌ ▐█████▌
+
""", u"""
aaaaaaabbbbbbbcccccccdddddddeeeeeeefffffggggggghhhhhhhiiijjjj
▐█ █▌ ▄█▌ ▐█ █▌ █▌
- ▐█ █▌ ▐█ ▐█
+ ▐█ █▌ ▐█ ▐█
▄███▄ ▐████▄ ▄███▄ ▄████▌ ▄███▄ ▐███ ▄███▄ ▐████▄ ▐█▌ ▐█▌
- ▄▄▄█▌▐█ █▌▐█ ▐█ █▌▐█▄▄▄█▌ ▐█ ▐█ █▌▐█ █▌ █▌ █▌
+ ▄▄▄█▌▐█ █▌▐█ ▐█ █▌▐█▄▄▄█▌ ▐█ ▐█ █▌▐█ █▌ █▌ █▌
▐█▀▀▀█▌▐█ █▌▐█ ▐█ █▌▐█▀▀▀ ▐█ ▐█▄▄▄█▌▐█ █▌ █▌ █▌
▀████▌▐████▀ ▀███▀ ▀████▌ ▀███▀ ▐█ ▀▀▀█▌▐█ █▌ █▌ █▌
- ▀███▀ ▐██
+ ▀███▀ ▐██
""", u"""
kkkkkkkllllmmmmmmmmnnnnnnnooooooopppppppqqqqqqqrrrrrrsssssss
-▐█ ██
-▐█ ▐█
-▐█ ▄█▌ ▐█ ▄█▌▐█▄ ▐████▄ ▄███▄ ▐████▄ ▄████▌ ▄███▌ ▄███▄
-▐█▄█▀ ▐█ ▐█ ▐▌ █▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌▐█ ▐█▄▄▄
+▐█ ██
+▐█ ▐█
+▐█ ▄█▌ ▐█ ▄█▌▐█▄ ▐████▄ ▄███▄ ▐████▄ ▄████▌ ▄███▌ ▄███▄
+▐█▄█▀ ▐█ ▐█ ▐▌ █▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌▐█ ▐█▄▄▄
▐█▀▀█▄ ▐█ ▐█ ▐▌ █▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌▐█ ▀▀▀█▌
-▐█ █▌ ▐█▌▐█ █▌▐█ █▌ ▀███▀ ▐████▀ ▀████▌▐█ ▀███▀
+▐█ █▌ ▐█▌▐█ █▌▐█ █▌ ▀███▀ ▐████▀ ▀████▌▐█ ▀███▀
▐█ █▌
""", u"""
tttttuuuuuuuvvvvvvvwwwwwwwwxxxxxxxyyyyyyyzzzzzzz
█▌
█▌
- ███▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌▐█████▌
- █▌ ▐█ █▌ █▌ ▐█ ▐█ █▌ ▀█▄█▀ ▐█ █▌ ▄█▀
+ ███▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌▐█ █▌▐█████▌
+ █▌ ▐█ █▌ █▌ ▐█ ▐█ █▌ ▀█▄█▀ ▐█ █▌ ▄█▀
█▌ ▐█ █▌ ███ ▐█ ▐▌ █▌ ▄█▀█▄ ▐█▄▄▄█▌ ▄█▀
█▌ ▀███▀ ▐█▌ ▀█▌▐█▀ ▐█ █▌ ▀▀▀█▌▐█████▌
- ▀███▀
+ ▀███▀
"""]
add_font("Half Block 7x7",HalfBlock7x7Font)
diff -Nru urwid-1.2.1/urwid/html_fragment.py urwid-1.3.0/urwid/html_fragment.py
--- urwid-1.2.1/urwid/html_fragment.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/html_fragment.py 2014-10-17 20:09:04.000000000 +0200
@@ -49,12 +49,12 @@
self.colors = 16
self.bright_is_bold = False # ignored
self.has_underline = True # ignored
- self.register_palette_entry(None,
+ self.register_palette_entry(None,
_default_foreground, _default_background)
def set_terminal_properties(self, colors=None, bright_is_bold=None,
has_underline=None):
-
+
if colors is None:
colors = self.colors
if bright_is_bold is None:
@@ -70,41 +70,31 @@
"""Not yet implemented"""
pass
- def start(self):
- pass
-
- def stop(self):
- pass
-
def set_input_timeouts(self, *args):
pass
def reset_default_terminal_palette(self, *args):
pass
- def run_wrapper(self,fn):
- """Call fn."""
- return fn()
-
def draw_screen(self, (cols, rows), r ):
- """Create an html fragment from the render object.
+ """Create an html fragment from the render object.
Append it to HtmlGenerator.fragments list.
"""
# collect output in l
l = []
-
+
assert r.rows() == rows
-
+
if r.cursor is not None:
cx, cy = r.cursor
else:
cx = cy = None
-
+
y = -1
for row in r.content():
y += 1
col = 0
-
+
for a, cs, run in row:
run = run.translate(_trans_table)
if isinstance(a, AttrSpec):
@@ -126,10 +116,10 @@
l.append(html_span(run, aspec))
l.append("\n")
-
+
# add the fragment to the list
self.fragments.append( "<pre>%s</pre>" % "".join(l) )
-
+
def clear(self):
"""
Force the screen to be completely repainted on the next
@@ -138,7 +128,7 @@
(does nothing for html_fragment)
"""
pass
-
+
def get_cols_rows(self):
"""Return the next screen size in HtmlGenerator.sizes."""
if not self.sizes:
@@ -173,9 +163,9 @@
def html_span(fg, bg, s):
if not s: return ""
return ('<span style="color:%s;'
- 'background:%s%s">%s</span>' %
+ 'background:%s%s">%s</span>' %
(fg, bg, extra, html_escape(s)))
-
+
if cursor >= 0:
c_off, _ign = util.calc_text_pos(s, 0, len(s), cursor)
c2_off = util.move_next_char(s, c_off, len(s))
@@ -195,17 +185,17 @@
def screenshot_init( sizes, keys ):
"""
- Replace curses_display.Screen and raw_display.Screen class with
+ Replace curses_display.Screen and raw_display.Screen class with
HtmlGenerator.
-
- Call this function before executing an application that uses
+
+ Call this function before executing an application that uses
curses_display.Screen to have that code use HtmlGenerator instead.
-
+
sizes -- list of ( columns, rows ) tuples to be returned by each call
to HtmlGenerator.get_cols_rows()
keys -- list of lists of keys to be returned by each call to
HtmlGenerator.get_input()
-
+
Lists of keys may include "window resize" to force the application to
call get_cols_rows and read a new screen size.
@@ -228,7 +218,7 @@
assert row>0 and col>0
except (AssertionError, ValueError):
raise Exception, "sizes must be in the form [ (col1,row1), (col2,row2), ...]"
-
+
try:
for l in keys:
assert type(l) == list
@@ -236,12 +226,12 @@
assert type(k) == str
except (AssertionError, ValueError):
raise Exception, "keys must be in the form [ [keyA1, keyA2, ..], [keyB1, ..], ...]"
-
+
import curses_display
curses_display.Screen = HtmlGenerator
import raw_display
raw_display.Screen = HtmlGenerator
-
+
HtmlGenerator.sizes = sizes
HtmlGenerator.keys = keys
@@ -252,4 +242,4 @@
HtmlGenerator.fragments = []
return l
-
+
diff -Nru urwid-1.2.1/urwid/__init__.py urwid-1.3.0/urwid/__init__.py
--- urwid-1.2.1/urwid/__init__.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/__init__.py 2014-10-17 20:09:04.000000000 +0200
@@ -53,7 +53,7 @@
CURSOR_PAGE_UP, CURSOR_PAGE_DOWN, CURSOR_MAX_LEFT, CURSOR_MAX_RIGHT,
ACTIVATE)
from urwid.main_loop import (ExitMainLoop, MainLoop, SelectEventLoop,
- GLibEventLoop, TornadoEventLoop)
+ GLibEventLoop, TornadoEventLoop, AsyncioEventLoop)
try:
from urwid.main_loop import TwistedEventLoop
except ImportError:
diff -Nru urwid-1.2.1/urwid/lcd_display.py urwid-1.3.0/urwid/lcd_display.py
--- urwid-1.2.1/urwid/lcd_display.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/lcd_display.py 2014-10-17 20:09:04.000000000 +0200
@@ -33,21 +33,12 @@
def set_mouse_tracking(self, enable=True):
pass
- def start(self):
- pass
-
- def stop(self):
- pass
-
def set_input_timeouts(self, *args):
pass
def reset_default_terminal_palette(self, *args):
pass
- def run_wrapper(self,fn):
- return fn()
-
def draw_screen(self, (cols, rows), r ):
pass
@@ -68,7 +59,7 @@
'right_press', 'enter_press', 'exit_press',
'up_release', 'down_release', 'left_release',
'right_release', 'enter_release', 'exit_release',
- 'ul_press', 'ur_press', 'll_press', 'lr_press',
+ 'ul_press', 'ur_press', 'll_press', 'lr_press',
'ul_release', 'ur_release', 'll_release', 'lr_release']
CMD_PING = 0
CMD_VERSION = 1
@@ -146,15 +137,15 @@
def _send_packet(self, command, data):
"""
- low-level packet sending.
- Following the protocol requires waiting for ack packet between
+ low-level packet sending.
+ Following the protocol requires waiting for ack packet between
sending each packet to the device.
"""
buf = chr(command) + chr(len(data)) + data
crc = self.get_crc(buf)
buf = buf + chr(crc & 0xff) + chr(crc >> 8)
self._device.write(buf)
-
+
def _read_packet(self):
"""
low-level packet reading.
@@ -171,7 +162,7 @@
self._unprocessed = unprocessed
return command, data
except self.MoreDataRequired:
- return
+ return
except self.InvalidPacket:
# throw out a byte and try to parse again
self._unprocessed = self._unprocessed[1:]
@@ -206,9 +197,9 @@
class KeyRepeatSimulator(object):
"""
- Provide simulated repeat key events when given press and
+ Provide simulated repeat key events when given press and
release events.
-
+
If two or more keys are pressed disable repeating until all
keys are released.
"""
@@ -236,7 +227,7 @@
def next_event(self):
"""
- Return (remaining, key) where remaining is the number of seconds
+ Return (remaining, key) where remaining is the number of seconds
(float) until the key repeat event should be sent, or None if no
events are pending.
"""
@@ -301,8 +292,8 @@
cursor_style = CFLCDScreen.CURSOR_INVERTING_BLINKING_BLOCK
- def __init__(self, device_path, baud=115200,
- repeat_delay=0.5, repeat_next=0.125,
+ def __init__(self, device_path, baud=115200,
+ repeat_delay=0.5, repeat_next=0.125,
key_map=['up', 'down', 'left', 'right', 'enter', 'esc']):
"""
device_path -- eg. '/dev/ttyUSB0'
@@ -357,7 +348,7 @@
if not packet:
break
command, data = packet
-
+
if command == self.CMD_KEY_ACTIVITY and data:
d0 = ord(data[0])
if 1 <= d0 <= 12:
@@ -374,7 +365,7 @@
elif command & 0xc0 == 0x40: # "ACK"
if command & 0x3f == self._last_command:
self._send_next_command()
-
+
next_repeat = self.key_repeat.next_event()
if next_repeat:
timeout, key = next_repeat
@@ -424,7 +415,7 @@
sb.append(text)
y += 1
- if (self._previous_canvas and
+ if (self._previous_canvas and
self._previous_canvas.cursor == canvas.cursor and
(not self._update_cursor or not canvas.cursor)):
pass
@@ -489,6 +480,6 @@
assert 0 <= led <= 3
assert rg in (0, 1)
assert 0 <= value <= 100
- self.queue_command(self.CMD_GPO, chr(12 - 2 * led - rg) +
+ self.queue_command(self.CMD_GPO, chr(12 - 2 * led - rg) +
chr(value))
diff -Nru urwid-1.2.1/urwid/main_loop.py urwid-1.3.0/urwid/main_loop.py
--- urwid-1.2.1/urwid/main_loop.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/main_loop.py 2014-10-17 20:09:04.000000000 +0200
@@ -25,12 +25,16 @@
import time
import heapq
import select
-import fcntl
import os
from functools import wraps
from weakref import WeakKeyDictionary
-from urwid.util import is_mouse_event
+try:
+ import fcntl
+except ImportError:
+ pass # windows
+
+from urwid.util import StoppingContext, is_mouse_event
from urwid.compat import PYTHON3
from urwid.command_map import command_map, REDRAW_SCREEN
from urwid.wimp import PopUpTarget
@@ -46,6 +50,9 @@
"""
pass
+class CantUseExternalLoop(Exception):
+ pass
+
class MainLoop(object):
"""
This is the standard main loop implementation for a single interactive
@@ -112,7 +119,7 @@
self._unhandled_input = unhandled_input
self._input_filter = input_filter
- if not hasattr(screen, 'get_input_descriptors'
+ if not hasattr(screen, 'hook_event_loop'
) and event_loop is not None:
raise NotImplementedError("screen object passed "
"%r does not support external event loops" % (screen,))
@@ -120,7 +127,6 @@
event_loop = SelectEventLoop()
self.event_loop = event_loop
- self._input_timeout = None
self._watch_pipes = {}
def _set_widget(self, widget):
@@ -264,14 +270,12 @@
Start the main loop handling input events and updating the screen. The
loop will continue until an :exc:`ExitMainLoop` exception is raised.
- This method will use :attr:`screen`'s run_wrapper() method if
- :attr:`screen`'s start() method has not already been called.
+ If you would prefer to manage the event loop yourself, don't use this
+ method. Instead, call :meth:`start` before starting the event loop,
+ and :meth:`stop` once it's finished.
"""
try:
- if self.screen.started:
- self._run()
- else:
- self.screen.run_wrapper(self._run)
+ self._run()
except ExitMainLoop:
pass
@@ -289,101 +293,106 @@
>>> evl.watch_file_rval = 2
>>> ml = MainLoop(w, [], scr, event_loop=evl)
>>> ml.run() # doctest:+ELLIPSIS
+ screen.start()
screen.set_mouse_tracking()
+ screen.unhook_event_loop(...)
+ screen.hook_event_loop(...)
+ event_loop.enter_idle(<bound method MainLoop.entering_idle...>)
+ event_loop.run()
+ event_loop.remove_enter_idle(1)
+ screen.unhook_event_loop(...)
+ screen.stop()
+ >>> ml.draw_screen() # doctest:+ELLIPSIS
screen.get_cols_rows()
widget.render((20, 10), focus=True)
screen.draw_screen((20, 10), 'fake canvas')
- screen.get_input_descriptors()
- event_loop.watch_file(42, <bound method ...>)
- event_loop.enter_idle(<bound method ...>)
- event_loop.run()
- event_loop.remove_enter_idle(1)
- event_loop.remove_watch_file(2)
- >>> scr.started = False
- >>> ml.run() # doctest:+ELLIPSIS
- screen.run_wrapper(<bound method ...>)
"""
- def _run(self):
- if self.handle_mouse:
- self.screen.set_mouse_tracking()
+ def start(self):
+ """
+ Sets up the main loop, hooking into the event loop where necessary.
+ Starts the :attr:`screen` if it hasn't already been started.
- if not hasattr(self.screen, 'get_input_descriptors'):
- return self._run_screen_event_loop()
+ If you want to control starting and stopping the event loop yourself,
+ you should call this method before starting, and call `stop` once the
+ loop has finished. You may also use this method as a context manager,
+ which will stop the loop automatically at the end of the block:
- self.draw_screen()
+ with main_loop.start():
+ ...
- fd_handles = []
- def reset_input_descriptors(only_remove=False):
- for handle in fd_handles:
- self.event_loop.remove_watch_file(handle)
- if only_remove:
- del fd_handles[:]
- else:
- fd_handles[:] = [
- self.event_loop.watch_file(fd, self._update)
- for fd in self.screen.get_input_descriptors()]
- if not fd_handles and self._input_timeout is not None:
- self.event_loop.remove_alarm(self._input_timeout)
+ Note that some event loop implementations don't handle exceptions
+ specially if you manage the event loop yourself. In particular, the
+ Twisted and asyncio loops won't stop automatically when
+ :exc:`ExitMainLoop` (or anything else) is raised.
+ """
+ self.screen.start()
+
+ if self.handle_mouse:
+ self.screen.set_mouse_tracking()
+
+ if not hasattr(self.screen, 'hook_event_loop'):
+ raise CantUseExternalLoop(
+ "Screen {0!r} doesn't support external event loops")
try:
signals.connect_signal(self.screen, INPUT_DESCRIPTORS_CHANGED,
- reset_input_descriptors)
+ self._reset_input_descriptors)
except NameError:
pass
# watch our input descriptors
- reset_input_descriptors()
- idle_handle = self.event_loop.enter_idle(self.entering_idle)
+ self._reset_input_descriptors()
+ self.idle_handle = self.event_loop.enter_idle(self.entering_idle)
- # Go..
- self.event_loop.run()
+ return StoppingContext(self)
- # tidy up
- self.event_loop.remove_enter_idle(idle_handle)
- reset_input_descriptors(True)
+ def stop(self):
+ """
+ Cleans up any hooks added to the event loop. Only call this if you're
+ managing the event loop yourself, after the loop stops.
+ """
+ self.event_loop.remove_enter_idle(self.idle_handle)
+ del self.idle_handle
signals.disconnect_signal(self.screen, INPUT_DESCRIPTORS_CHANGED,
- reset_input_descriptors)
+ self._reset_input_descriptors)
+ self.screen.unhook_event_loop(self.event_loop)
+
+ self.screen.stop()
+
+ def _reset_input_descriptors(self):
+ self.screen.unhook_event_loop(self.event_loop)
+ self.screen.hook_event_loop(self.event_loop, self._update)
+
+ def _run(self):
+ try:
+ self.start()
+ except CantUseExternalLoop:
+ try:
+ return self._run_screen_event_loop()
+ finally:
+ self.screen.stop()
- def _update(self, timeout=False):
+ self.event_loop.run()
+ self.stop()
+
+ def _update(self, keys, raw):
"""
>>> w = _refl("widget")
>>> w.selectable_rval = True
>>> w.mouse_event_rval = True
>>> scr = _refl("screen")
>>> scr.get_cols_rows_rval = (15, 5)
- >>> scr.get_input_nonblocking_rval = 1, ['y'], [121]
>>> evl = _refl("event_loop")
>>> ml = MainLoop(w, [], scr, event_loop=evl)
>>> ml._input_timeout = "old timeout"
- >>> ml._update() # doctest:+ELLIPSIS
- event_loop.remove_alarm('old timeout')
- screen.get_input_nonblocking()
- event_loop.alarm(1, <function ...>)
+ >>> ml._update(['y'], [121]) # doctest:+ELLIPSIS
screen.get_cols_rows()
widget.selectable()
widget.keypress((15, 5), 'y')
- >>> scr.get_input_nonblocking_rval = None, [("mouse press", 1, 5, 4)
- ... ], []
- >>> ml._update()
- screen.get_input_nonblocking()
+ >>> ml._update([("mouse press", 1, 5, 4)], [])
widget.mouse_event((15, 5), 'mouse press', 1, 5, 4, focus=True)
- >>> scr.get_input_nonblocking_rval = None, [], []
- >>> ml._update()
- screen.get_input_nonblocking()
- """
- if self._input_timeout is not None and not timeout:
- # cancel the timeout, something else triggered the update
- self.event_loop.remove_alarm(self._input_timeout)
- self._input_timeout = None
-
- max_wait, keys, raw = self.screen.get_input_nonblocking()
-
- if max_wait is not None:
- # if get_input_nonblocking wants to be called back
- # make sure it happens with an alarm
- self._input_timeout = self.event_loop.alarm(max_wait,
- lambda: self._update(timeout=True))
-
+ >>> ml._update([], [])
+ """
keys = self.input_filter(keys, raw)
if keys:
@@ -415,7 +424,7 @@
else:
self.screen.set_input_timeouts(None)
keys, raw = self.screen.get_input(True)
- if not keys and next_alarm:
+ if not keys and next_alarm:
sec = next_alarm[0] - time.time()
if sec <= 0:
break
@@ -579,7 +588,7 @@
def alarm(self, seconds, callback):
"""
- Call callback() given time from from now. No parameters are
+ Call callback() a given time from now. No parameters are
passed to callback.
Returns a handle that may be passed to remove_alarm()
@@ -667,7 +676,7 @@
while True:
try:
self._loop()
- except select.error, e:
+ except select.error as e:
if e.args[0] != 4:
# not just something we need to retry
raise
@@ -683,7 +692,7 @@
if self._alarms:
tm = self._alarms[0][0]
timeout = max(0, tm - time.time())
- if self._did_something and (not self._alarms or
+ if self._did_something and (not self._alarms or
(self._alarms and timeout > 0)):
timeout = 0
tm = 'idle'
@@ -726,7 +735,7 @@
def alarm(self, seconds, callback):
"""
- Call callback() given time from from now. No parameters are
+ Call callback() a given time from now. No parameters are
passed to callback.
Returns a handle that may be passed to remove_alarm()
@@ -1040,6 +1049,10 @@
``manage_reactor=False`` and take care of running/stopping the reactor
at the beginning/ending of your program yourself.
+ You can also forego using :class:`MainLoop`'s run() entirely, and
+ instead call start() and stop() before and after starting the
+ reactor.
+
.. _Twisted: http://twistedmatrix.com/trac/
"""
if reactor is None:
@@ -1057,7 +1070,7 @@
def alarm(self, seconds, callback):
"""
- Call callback() given time from from now. No parameters are
+ Call callback() a given time from now. No parameters are
passed to callback.
Returns a handle that may be passed to remove_alarm()
@@ -1196,6 +1209,121 @@
return wrapper
+class AsyncioEventLoop(object):
+ """
+ Event loop based on the standard library ``asyncio`` module.
+
+ ``asyncio`` is new in Python 3.4, but also exists as a backport on PyPI for
+ Python 3.3. The ``trollius`` package is available for older Pythons with
+ slightly different syntax, but also works with this loop.
+ """
+ _we_started_event_loop = False
+
+ _idle_emulation_delay = 1.0/256 # a short time (in seconds)
+
+ def __init__(self, **kwargs):
+ if 'loop' in kwargs:
+ self._loop = kwargs.pop('loop')
+ else:
+ import asyncio
+ self._loop = asyncio.get_event_loop()
+
+ def alarm(self, seconds, callback):
+ """
+ Call callback() a given time from now. No parameters are
+ passed to callback.
+
+ Returns a handle that may be passed to remove_alarm()
+
+ seconds -- time in seconds to wait before calling callback
+ callback -- function to call from event loop
+ """
+ return self._loop.call_later(seconds, callback)
+
+ def remove_alarm(self, handle):
+ """
+ Remove an alarm.
+
+ Returns True if the alarm exists, False otherwise
+ """
+ existed = not handle._cancelled
+ handle.cancel()
+ return existed
+
+ def watch_file(self, fd, callback):
+ """
+ Call callback() when fd has some data to read. No parameters
+ are passed to callback.
+
+ Returns a handle that may be passed to remove_watch_file()
+
+ fd -- file descriptor to watch for input
+ callback -- function to call when input is available
+ """
+ self._loop.add_reader(fd, callback)
+ return fd
+
+ def remove_watch_file(self, handle):
+ """
+ Remove an input file.
+
+ Returns True if the input file exists, False otherwise
+ """
+ return self._loop.remove_reader(handle)
+
+ def enter_idle(self, callback):
+ """
+ Add a callback for entering idle.
+
+ Returns a handle that may be passed to remove_idle()
+ """
+ # XXX there's no such thing as "idle" in most event loops; this fakes
+ # it the same way as Twisted, by scheduling the callback to be called
+ # repeatedly
+ mutable_handle = [None]
+ def faux_idle_callback():
+ callback()
+ mutable_handle[0] = self._loop.call_later(
+ self._idle_emulation_delay, faux_idle_callback)
+
+ mutable_handle[0] = self._loop.call_later(
+ self._idle_emulation_delay, faux_idle_callback)
+
+ return mutable_handle
+
+ def remove_enter_idle(self, handle):
+ """
+ Remove an idle callback.
+
+ Returns True if the handle was removed.
+ """
+ # `handle` is just a list containing the current actual handle
+ return self.remove_alarm(handle[0])
+
+ _exc_info = None
+
+ def _exception_handler(self, loop, context):
+ exc = context.get('exception')
+ if exc:
+ loop.stop()
+ if not isinstance(exc, ExitMainLoop):
+ # Store the exc_info so we can re-raise after the loop stops
+ import sys
+ self._exc_info = sys.exc_info()
+ else:
+ loop.default_exception_handler(context)
+
+ def run(self):
+ """
+ Start the event loop. Exit the loop when any callback raises
+ an exception. If ExitMainLoop is raised, exit cleanly.
+ """
+ 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]
+ self._exc_info = None
+
def _refl(name, rval=None, exit=False):
"""
diff -Nru urwid-1.2.1/urwid/monitored_list.py urwid-1.3.0/urwid/monitored_list.py
--- urwid-1.2.1/urwid/monitored_list.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/monitored_list.py 2014-10-17 20:09:04.000000000 +0200
@@ -158,9 +158,9 @@
self._focus = 0
return
if index < 0 or index >= len(self):
- raise IndexError, 'focus index is out of range: %s' % (index,)
+ raise IndexError('focus index is out of range: %s' % (index,))
if index != int(index):
- raise IndexError, 'invalid focus index: %s' % (index,)
+ raise IndexError('invalid focus index: %s' % (index,))
index = int(index)
if index != self._focus:
self._focus_changed(index)
@@ -265,8 +265,10 @@
def __delitem__(self, y):
"""
- >>> ml = MonitoredFocusList([0,1,2,3], focus=2)
+ >>> ml = MonitoredFocusList([0,1,2,3,4], focus=2)
>>> del ml[3]; ml
+ MonitoredFocusList([0, 1, 2, 4], focus=2)
+ >>> del ml[-1]; ml
MonitoredFocusList([0, 1, 2], focus=2)
>>> del ml[0]; ml
MonitoredFocusList([1, 2], focus=1)
@@ -279,11 +281,19 @@
MonitoredFocusList([5, 6, 5, 6, 5], focus=2)
>>> del ml[::2]; ml
MonitoredFocusList([6, 6], focus=1)
+ >>> ml = MonitoredFocusList([0,1,2,3,4,6,7], focus=2)
+ >>> del ml[-2:]; ml
+ MonitoredFocusList([0, 1, 2, 3, 4], focus=2)
+ >>> del ml[-4:-2]; ml
+ MonitoredFocusList([0, 3, 4], focus=1)
+ >>> del ml[:]; ml
+ MonitoredFocusList([], focus=None)
"""
if isinstance(y, slice):
focus = self._adjust_focus_on_contents_modified(y)
else:
- focus = self._adjust_focus_on_contents_modified(slice(y, y+1))
+ focus = self._adjust_focus_on_contents_modified(slice(y,
+ y+1 or None))
rval = super(MonitoredFocusList, self).__delitem__(y)
self._set_focus(focus)
return rval
@@ -308,6 +318,14 @@
range(1, 4, 2) <- [12, 13]
>>> ml[::2] = [10, 11]
range(0, 4, 2) <- [10, 11]
+ >>> ml[-3:-1] = [21, 22, 23]
+ range(1, 3, 1) <- [21, 22, 23]
+ >>> ml
+ MonitoredFocusList([10, 21, 22, 23, 13], focus=2)
+ >>> ml[:] = []
+ range(0, 5, 1) <- []
+ >>> ml
+ MonitoredFocusList([], focus=None)
"""
if isinstance(i, slice):
focus = self._adjust_focus_on_contents_modified(i, y)
@@ -319,51 +337,10 @@
if not PYTHON3:
def __delslice__(self, i, j):
- """
- >>> def modified(indices, new_items):
- ... print "range%r <- %r" % (indices, list(new_items))
- >>> ml = MonitoredFocusList([0,1,2,3,4], focus=2)
- >>> ml.set_validate_contents_modified(modified)
- >>> del ml[3:5]
- range(3, 5, 1) <- []
- >>> ml
- MonitoredFocusList([0, 1, 2], focus=2)
- >>> del ml[:1]
- range(0, 1, 1) <- []
- >>> ml
- MonitoredFocusList([1, 2], focus=1)
- >>> del ml[1:]; ml
- range(1, 2, 1) <- []
- MonitoredFocusList([1], focus=0)
- >>> del ml[:]; ml
- range(0, 1, 1) <- []
- MonitoredFocusList([], focus=None)
- """
- focus = self._adjust_focus_on_contents_modified(slice(i, j))
- rval = super(MonitoredFocusList, self).__delslice__(i, j)
- self._set_focus(focus)
- return rval
+ return self.__delitem__(slice(i,j))
def __setslice__(self, i, j, y):
- """
- >>> ml = MonitoredFocusList([0,1,2,3,4], focus=2)
- >>> ml[3:5] = [-1]; ml
- MonitoredFocusList([0, 1, 2, -1], focus=2)
- >>> ml[0:1] = []; ml
- MonitoredFocusList([1, 2, -1], focus=1)
- >>> ml[1:] = [3, 4]; ml
- MonitoredFocusList([1, 3, 4], focus=1)
- >>> ml[1:] = [2]; ml
- MonitoredFocusList([1, 2], focus=1)
- >>> ml[0:1] = [9,9,9]; ml
- MonitoredFocusList([9, 9, 9, 2], focus=3)
- >>> ml[:] = []; ml
- MonitoredFocusList([], focus=None)
- """
- focus = self._adjust_focus_on_contents_modified(slice(i, j), y)
- rval = super(MonitoredFocusList, self).__setslice__(i, j, y)
- self._set_focus(focus)
- return rval
+ return self.__setitem__(slice(i, j), y)
def __imul__(self, n):
"""
@@ -484,7 +461,7 @@
self._set_focus(max(0, len(self) - self._focus - 1))
return rval
- def sort(self):
+ def sort(self, **kwargs):
"""
>>> ml = MonitoredFocusList([-2,0,1,-3,2,-1,3], focus=4)
>>> ml.sort(); ml
@@ -493,7 +470,7 @@
if not self:
return
value = self[self._focus]
- rval = super(MonitoredFocusList, self).sort()
+ rval = super(MonitoredFocusList, self).sort(**kwargs)
self._set_focus(self.index(value))
return rval
diff -Nru urwid-1.2.1/urwid/old_str_util.py urwid-1.3.0/urwid/old_str_util.py
--- urwid-1.2.1/urwid/old_str_util.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/old_str_util.py 2014-10-17 20:09:04.000000000 +0200
@@ -19,6 +19,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Urwid web site: http://excess.org/urwid/
+from __future__ import print_function
import re
@@ -30,7 +31,7 @@
_byte_encoding = None
# GENERATED DATA
-# generated from
+# generated from
# http://www.unicode.org/Public/4.0-Update/EastAsianWidth-4.0.0.txt
widths = [
@@ -92,7 +93,7 @@
"""
assert isinstance(text, bytes), text
b1 = ord2(text[pos])
- if not b1 & 0x80:
+ if not b1 & 0x80:
return b1, pos+1
error = ord("?"), pos+1
lt = len(text)
@@ -189,7 +190,7 @@
while i < end_offs:
o, n = decode(text, i)
w = get_width(o)
- if w+sc > pref_col:
+ if w+sc > pref_col:
return i, sc
i = n
sc += w
@@ -350,18 +351,18 @@
if last is None:
out.append((0, l))
last = l
-
+
if last == l:
out[-1] = (num, l)
else:
out.append( (num, l) )
last = l
- print "widths = ["
+ print("widths = [")
for o in out[1:]: # treat control characters same as ascii
- print "\t%r," % (o,)
- print "]"
-
+ print("\t%r," % (o,))
+ print("]")
+
if __name__ == "__main__":
process_east_asian_width()
diff -Nru urwid-1.2.1/urwid/raw_display.py urwid-1.3.0/urwid/raw_display.py
--- urwid-1.2.1/urwid/raw_display.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/raw_display.py 2014-10-17 20:09:04.000000000 +0200
@@ -23,15 +23,19 @@
Direct terminal UI implementation
"""
-import fcntl
-import termios
import os
import select
import struct
import sys
-import tty
import signal
+try:
+ import fcntl
+ import termios
+ import tty
+except ImportError:
+ pass # windows
+
from urwid import util
from urwid import escape
from urwid.display_common import BaseScreen, RealTerminal, \
@@ -44,14 +48,14 @@
class Screen(BaseScreen, RealTerminal):
- def __init__(self):
+ def __init__(self, input=sys.stdin, output=sys.stdout):
"""Initialize a screen that directly prints escape codes to an output
terminal.
"""
super(Screen, self).__init__()
self._pal_escape = {}
self._pal_attrspec = {}
- signals.connect_signal(self, UPDATE_PALETTE_ENTRY,
+ signals.connect_signal(self, UPDATE_PALETTE_ENTRY,
self._on_update_palette_entry)
self.colors = 16 # FIXME: detect this
self.has_underline = True # FIXME: detect this
@@ -71,11 +75,15 @@
self._rows_used = None
self._cy = 0
term = os.environ.get('TERM', '')
- self.bright_is_bold = not term.startswith("xterm")
+ self.fg_bright_is_bold = not term.startswith("xterm")
+ self.bg_bright_is_blink = (term == "linux")
self.back_color_erase = not term.startswith("screen")
self._next_timeout = None
- self._term_output_file = sys.stdout
- self._term_input_file = sys.stdin
+
+ # Our connections to the world
+ self._term_output_file = output
+ self._term_input_file = input
+
# pipe for signalling external event loops about resize events
self._resize_pipe_rd, self._resize_pipe_wr = os.pipe()
fcntl.fcntl(self._resize_pipe_rd, fcntl.F_SETFL, os.O_NONBLOCK)
@@ -86,12 +94,12 @@
self._pal_attrspec[name] = a
self._pal_escape[name] = self._attrspec_to_escape(a)
- def set_input_timeouts(self, max_wait=None, complete_wait=0.125,
+ def set_input_timeouts(self, max_wait=None, complete_wait=0.125,
resize_wait=0.125):
"""
Set the get_input timeout values. All values are in floating
point numbers of seconds.
-
+
max_wait -- amount of time in seconds to wait for input when
there is no input pending, wait forever if None
complete_wait -- amount of time in seconds to wait when
@@ -160,10 +168,10 @@
def _mouse_tracking(self, enable):
if enable:
- self._term_output_file.write(escape.MOUSE_TRACKING_ON)
+ self.write(escape.MOUSE_TRACKING_ON)
self._start_gpm_tracking()
else:
- self._term_output_file.write(escape.MOUSE_TRACKING_OFF)
+ self.write(escape.MOUSE_TRACKING_OFF)
self._stop_gpm_tracking()
def _start_gpm_tracking(self):
@@ -185,15 +193,14 @@
os.waitpid(self.gpm_mev.pid, 0)
self.gpm_mev = None
- def start(self, alternate_buffer=True):
+ def _start(self, alternate_buffer=True):
"""
Initialize the screen and input mode.
alternate_buffer -- use alternate screen buffer
"""
- assert not self._started
if alternate_buffer:
- self._term_output_file.write(escape.SWITCH_TO_ALTERNATE_BUFFER)
+ self.write(escape.SWITCH_TO_ALTERNATE_BUFFER)
self._rows_used = None
else:
self._rows_used = 0
@@ -205,25 +212,22 @@
self.signal_init()
self._alternate_buffer = alternate_buffer
- self._input_iter = self._run_input_iter()
self._next_timeout = self.max_wait
if not self._signal_keys_set:
self._old_signal_keys = self.tty_signal_keys(fileno=fd)
- super(Screen, self).start()
-
signals.emit_signal(self, INPUT_DESCRIPTORS_CHANGED)
# restore mouse tracking to previous state
self._mouse_tracking(self._mouse_tracking_enabled)
- def stop(self):
+ return super(Screen, self)._start()
+
+ def _stop(self):
"""
Restore the screen.
"""
self.clear()
- if not self._started:
- return
signals.emit_signal(self, INPUT_DESCRIPTORS_CHANGED)
@@ -242,32 +246,33 @@
elif self.maxrow is not None:
move_cursor = escape.set_cursor_position(
0, self.maxrow)
- self._term_output_file.write(
+ self.write(
self._attrspec_to_escape(AttrSpec('',''))
+ escape.SI
+ move_cursor
+ escape.SHOW_CURSOR)
- self._input_iter = self._fake_input_iter()
if self._old_signal_keys:
self.tty_signal_keys(*(self._old_signal_keys + (fd,)))
- super(Screen, self).stop()
+ super(Screen, self)._stop()
+
+ def write(self, data):
+ """Write some data to the terminal.
- def run_wrapper(self, fn, alternate_buffer=True):
+ You may wish to override this if you're using something other than
+ regular files for input and output.
"""
- Call start to initialize screen, then call fn.
- When fn exits call stop to restore the screen to normal.
+ self._term_output_file.write(data)
- alternate_buffer -- use alternate screen buffer and restore
- normal screen buffer on exit
+ def flush(self):
+ """Flush the output buffer.
+
+ You may wish to override this if you're using something other than
+ regular files for input and output.
"""
- try:
- self.start(alternate_buffer)
- return fn()
- finally:
- self.stop()
+ self._term_output_file.flush()
def get_input(self, raw_keys=False):
"""Return pending input as a list.
@@ -285,7 +290,7 @@
Examples of keys returned:
- * ASCII printable characters: " ", "a", "0", "A", "-", "/"
+ * ASCII printable characters: " ", "a", "0", "A", "-", "/"
* ASCII control characters: "tab", "enter"
* Escape sequences: "up", "page up", "home", "insert", "f1"
* Key combinations: "shift f1", "meta a", "ctrl b"
@@ -305,7 +310,7 @@
Examples of mouse events returned:
- * Mouse button press: ('mouse press', 1, 15, 13),
+ * Mouse button press: ('mouse press', 1, 15, 13),
('meta mouse press', 2, 17, 23)
* Mouse drag: ('mouse drag', 1, 16, 13),
('mouse drag', 1, 17, 13),
@@ -316,17 +321,16 @@
assert self._started
self._wait_for_input_ready(self._next_timeout)
- self._next_timeout, keys, raw = self._input_iter.next()
+ keys, raw = self.parse_input(None, None, self.get_available_raw_input())
# Avoid pegging CPU at 100% when slowly resizing
if keys==['window resize'] and self.prev_input_resize:
while True:
self._wait_for_input_ready(self.resize_wait)
- self._next_timeout, keys, raw2 = \
- self._input_iter.next()
+ keys, raw2 = self.parse_input(None, None, self.get_available_raw_input())
raw += raw2
#if not keys:
- # keys, raw2 = self._get_input(
+ # keys, raw2 = self._get_input(
# self.resize_wait)
# raw += raw2
if keys!=['window resize']:
@@ -360,71 +364,135 @@
fd_list.append(self.gpm_mev.stdout.fileno())
return fd_list
- def get_input_nonblocking(self):
+ _current_event_loop_handles = ()
+
+ def unhook_event_loop(self, event_loop):
+ """
+ Remove any hooks added by hook_event_loop.
"""
- Return a (next_input_timeout, keys_pressed, raw_keycodes)
- tuple.
+ for handle in self._current_event_loop_handles:
+ event_loop.remove_watch_file(handle)
- Use this method if you are implementing your own event loop.
+ if self._input_timeout:
+ event_loop.remove_alarm(self._input_timeout)
+ self._input_timeout = None
- When there is input waiting on one of the descriptors returned
- by get_input_descriptors() this method should be called to
- read and process the input.
-
- This method expects to be called in next_input_timeout seconds
- (a floating point number) if there is no input waiting.
- """
- return self._input_iter.next()
-
- def _run_input_iter(self):
- def empty_resize_pipe():
- # clean out the pipe used to signal external event loops
- # that a resize has occurred
- try:
- while True: os.read(self._resize_pipe_rd, 1)
- except OSError:
- pass
+ def hook_event_loop(self, event_loop, callback):
+ """
+ Register the given callback with the event loop, to be called with new
+ input whenever it's available. The callback should be passed a list of
+ processed keys and a list of unprocessed keycodes.
- while True:
- processed = []
- codes = self._get_gpm_codes() + \
- self._get_keyboard_codes()
+ Subclasses may wish to use parse_input to wrap the callback.
+ """
+ if hasattr(self, 'get_input_nonblocking'):
+ wrapper = self._make_legacy_input_wrapper(event_loop, callback)
+ else:
+ wrapper = lambda: self.parse_input(
+ event_loop, callback, self.get_available_raw_input())
+ fds = self.get_input_descriptors()
+ handles = []
+ for fd in fds:
+ event_loop.watch_file(fd, wrapper)
+ self._current_event_loop_handles = handles
- original_codes = codes
- try:
- while codes:
- run, codes = escape.process_keyqueue(
- codes, True)
- processed.extend(run)
- except escape.MoreInputRequired:
- k = len(original_codes) - len(codes)
- yield (self.complete_wait, processed,
- original_codes[:k])
- empty_resize_pipe()
- original_codes = codes
- processed = []
-
- codes += self._get_keyboard_codes() + \
- self._get_gpm_codes()
- while codes:
- run, codes = escape.process_keyqueue(
- codes, False)
- processed.extend(run)
-
- if self._resized:
- processed.append('window resize')
- self._resized = False
+ _input_timeout = None
+ _partial_codes = None
- yield (self.max_wait, processed, original_codes)
- empty_resize_pipe()
+ def _make_legacy_input_wrapper(self, event_loop, callback):
+ """
+ Support old Screen classes that still have a get_input_nonblocking and
+ expect it to work.
+ """
+ def wrapper():
+ if self._input_timeout:
+ event_loop.remove_alarm(self._input_timeout)
+ self._input_timeout = None
+ timeout, keys, raw = self.get_input_nonblocking()
+ if timeout is not None:
+ self._input_timeout = event_loop.alarm(timeout, wrapper)
+
+ callback(keys, raw)
- def _fake_input_iter(self):
+ return wrapper
+
+ def get_available_raw_input(self):
"""
- This generator is a placeholder for when the screen is stopped
- to always return that no input is available.
+ Return any currently-available input. Does not block.
+
+ This method is only used by the default `hook_event_loop`
+ implementation; you can safely ignore it if you implement your own.
"""
- while True:
- yield (self.max_wait, [], [])
+ codes = self._get_gpm_codes() + self._get_keyboard_codes()
+
+ if self._partial_codes:
+ codes = self._partial_codes + codes
+ self._partial_codes = None
+
+ # clean out the pipe used to signal external event loops
+ # that a resize has occurred
+ try:
+ while True: os.read(self._resize_pipe_rd, 1)
+ except OSError:
+ pass
+
+ return codes
+
+ def parse_input(self, event_loop, callback, codes, wait_for_more=True):
+ """
+ Read any available input from get_available_raw_input, parses it into
+ keys, and calls the given callback.
+
+ The current implementation tries to avoid any assumptions about what
+ the screen or event loop look like; it only deals with parsing keycodes
+ and setting a timeout when an incomplete one is detected.
+
+ `codes` should be a sequence of keycodes, i.e. bytes. A bytearray is
+ appropriate, but beware of using bytes, which only iterates as integers
+ on Python 3.
+ """
+ # Note: event_loop may be None for 100% synchronous support, only used
+ # by get_input. Not documented because you shouldn't be doing it.
+ if self._input_timeout and event_loop:
+ event_loop.remove_alarm(self._input_timeout)
+ self._input_timeout = None
+
+ original_codes = codes
+ processed = []
+ try:
+ while codes:
+ run, codes = escape.process_keyqueue(
+ codes, wait_for_more)
+ processed.extend(run)
+ except escape.MoreInputRequired:
+ # Set a timer to wait for the rest of the input; if it goes off
+ # without any new input having come in, use the partial input
+ k = len(original_codes) - len(codes)
+ processed_codes = original_codes[:k]
+ self._partial_codes = codes
+
+ def _parse_incomplete_input():
+ self._input_timeout = None
+ self._partial_codes = None
+ self.parse_input(
+ event_loop, callback, codes, wait_for_more=False)
+ if event_loop:
+ self._input_timeout = event_loop.alarm(
+ self.complete_wait, _parse_incomplete_input)
+
+ else:
+ processed_codes = original_codes
+ self._partial_codes = None
+
+ if self._resized:
+ processed.append('window resize')
+ self._resized = False
+
+ if callback:
+ callback(processed, processed_codes)
+ else:
+ # For get_input
+ return processed, processed_codes
def _get_keyboard_codes(self):
codes = []
@@ -440,7 +508,7 @@
try:
while self.gpm_mev is not None and self.gpm_event_pending:
codes.extend(self._encode_gpm_event())
- except IOError, e:
+ except IOError as e:
if e.args[0] != 11:
raise
return codes
@@ -459,14 +527,14 @@
ready,w,err = select.select(
fd_list,[],fd_list, timeout)
break
- except select.error, e:
- if e.args[0] != 4:
+ except select.error as e:
+ if e.args[0] != 4:
raise
if self._resized:
ready = []
break
- return ready
-
+ return ready
+
def _getch(self, timeout):
ready = self._wait_for_input_ready(timeout)
if self.gpm_mev is not None:
@@ -475,7 +543,7 @@
if self._term_input_file.fileno() in ready:
return ord(os.read(self._term_input_file.fileno(), 1))
return -1
-
+
def _encode_gpm_event( self ):
self.gpm_event_pending = False
s = self.gpm_mev.stdout.readline().decode('ascii')
@@ -496,7 +564,7 @@
last = next = self.last_bstate
l = []
-
+
mod = 0
if m & 1: mod |= 4 # shift
if m & 10: mod |= 8 # alt
@@ -561,11 +629,11 @@
self.last_bstate = next
return l
-
+
def _getch_nodelay(self):
return self._getch(0)
-
-
+
+
def get_cols_rows(self):
"""Return the terminal dimensions (num columns, num rows)."""
y, x = 80, 24
@@ -585,17 +653,17 @@
"""
if self._setup_G1_done:
return
-
+
while True:
try:
- self._term_output_file.write(escape.DESIGNATE_G1_SPECIAL)
- self._term_output_file.flush()
+ self.write(escape.DESIGNATE_G1_SPECIAL)
+ self.flush()
break
except IOError:
pass
self._setup_G1_done = True
-
+
def draw_screen(self, (maxcol, maxrow), r ):
"""Paint screen with rendered canvas."""
assert self._started
@@ -607,13 +675,13 @@
return
self._setup_G1()
-
- if self._resized:
+
+ if self._resized:
# handle resize before trying to draw screen
return
-
+
o = [escape.HIDE_CURSOR, self._attrspec_to_escape(AttrSpec('',''))]
-
+
def partial_display():
# returns True if the screen is in partial display mode
# ie. only some rows belong to the display
@@ -633,9 +701,9 @@
def set_cursor_home():
if not partial_display():
return escape.set_cursor_position(0, 0)
- return (escape.CURSOR_HOME_COL +
+ return (escape.CURSOR_HOME_COL +
escape.move_cursor_up(cy))
-
+
def set_cursor_row(y):
if not partial_display():
return escape.set_cursor_position(0, y)
@@ -651,7 +719,7 @@
return ('\b' + escape.CURSOR_HOME_COL +
escape.move_cursor_down(y - cy) +
escape.move_cursor_right(x))
-
+
def is_blank_row(row):
if len(row) > 1:
return False
@@ -678,7 +746,7 @@
cy = 0
for row in r.content():
y += 1
- if False and osb and osb[y] == row:
+ if osb and osb[y] == row:
# this row of the screen buffer matches what is
# currently displayed, so we can skip this line
sb.append( osb[y] )
@@ -743,7 +811,7 @@
icss = escape.IBMPC_ON
else:
icss = escape.SO
- o += [ "\x08"*back,
+ o += [ "\x08"*back,
ias, icss,
escape.INSERT_ON, inserttext,
escape.INSERT_OFF ]
@@ -766,9 +834,9 @@
for l in o:
if isinstance(l, bytes) and PYTHON3:
l = l.decode('utf-8')
- self._term_output_file.write(l)
- self._term_output_file.flush()
- except IOError, e:
+ self.write(l)
+ self.flush()
+ except IOError as e:
# ignore interrupted syscall
if e.args[0] != 4:
raise
@@ -791,21 +859,21 @@
new_row = row[:-1]
z_attr, z_cs, last_text = row[-1]
last_cols = util.calc_width(last_text, 0, len(last_text))
- last_offs, z_col = util.calc_text_pos(last_text, 0,
+ last_offs, z_col = util.calc_text_pos(last_text, 0,
len(last_text), last_cols-1)
if last_offs == 0:
z_text = last_text
del new_row[-1]
# we need another segment
y_attr, y_cs, nlast_text = row[-2]
- nlast_cols = util.calc_width(nlast_text, 0,
+ nlast_cols = util.calc_width(nlast_text, 0,
len(nlast_text))
z_col += nlast_cols
nlast_offs, y_col = util.calc_text_pos(nlast_text, 0,
len(nlast_text), nlast_cols-1)
y_text = nlast_text[nlast_offs:]
if nlast_offs:
- new_row.append((y_attr, y_cs,
+ new_row.append((y_attr, y_cs,
nlast_text[:nlast_offs]))
else:
z_text = last_text[last_offs:]
@@ -818,12 +886,12 @@
if nlast_offs:
new_row.append((y_attr, y_cs,
last_text[:nlast_offs]))
-
+
new_row.append((z_attr, z_cs, z_text))
return new_row, z_col-y_col, (y_attr, y_cs, y_text)
-
-
+
+
def clear(self):
"""
Force the screen to be completely repainted on the next
@@ -832,7 +900,7 @@
self.screen_buf = None
self.setup_G1 = True
-
+
def _attrspec_to_escape(self, a):
"""
Convert AttrSpec instance a to an escape sequence for the terminal
@@ -849,7 +917,7 @@
fg = "38;5;%d" % a.foreground_number
elif a.foreground_basic:
if a.foreground_number > 7:
- if self.bright_is_bold:
+ if self.fg_bright_is_bold:
fg = "1;%d" % (a.foreground_number - 8 + 30)
else:
fg = "%d" % (a.foreground_number - 8 + 90)
@@ -863,8 +931,11 @@
bg = "48;5;%d" % a.background_number
elif a.background_basic:
if a.background_number > 7:
- # this doesn't work on most terminals
- bg = "%d" % (a.background_number - 8 + 100)
+ if self.bg_bright_is_blink:
+ bg = "5;%d" % (a.background_number - 8 + 40)
+ else:
+ # this doesn't work on most terminals
+ bg = "%d" % (a.background_number + 100)
else:
bg = "%d" % (a.background_number + 40)
else:
@@ -877,7 +948,7 @@
"""
colors -- number of colors terminal supports (1, 16, 88 or 256)
or None to leave unchanged
- bright_is_bold -- set to True if this terminal uses the bold
+ bright_is_bold -- set to True if this terminal uses the bold
setting to create bright colors (numbers 8-15), set to False
if this Terminal can create bright colors without bold or
None to leave unchanged
@@ -888,18 +959,18 @@
if colors is None:
colors = self.colors
if bright_is_bold is None:
- bright_is_bold = self.bright_is_bold
+ bright_is_bold = self.fg_bright_is_bold
if has_underline is None:
has_underline = self.has_underline
- if colors == self.colors and bright_is_bold == self.bright_is_bold \
+ if colors == self.colors and bright_is_bold == self.fg_bright_is_bold \
and has_underline == self.has_underline:
return
self.colors = colors
- self.bright_is_bold = bright_is_bold
+ self.fg_bright_is_bold = bright_is_bold
self.has_underline = has_underline
-
+
self.clear()
self._pal_escape = {}
for p,v in self._palette.items():
@@ -910,7 +981,7 @@
def reset_default_terminal_palette(self):
"""
Attempt to set the terminal palette to default values as taken
- from xterm. Uses number of colors from current
+ from xterm. Uses number of colors from current
set_terminal_properties() screen setting.
"""
if self.colors == 1:
@@ -934,21 +1005,21 @@
Attempt to set part of the terminal palette (this does not work
on all terminals.) The changes are sent as a single escape
sequence so they should all take effect at the same time.
-
+
0 <= index < 256 (some terminals will only have 16 or 88 colors)
0 <= red, green, blue < 256
"""
modify = ["%d;rgb:%02x/%02x/%02x" % (index, red, green, blue)
for index, red, green, blue in entries]
- self._term_output_file.write("\x1b]4;"+";".join(modify)+"\x1b\\")
- self._term_output_file.flush()
+ self.write("\x1b]4;"+";".join(modify)+"\x1b\\")
+ self.flush()
# shortcut for creating an AttrSpec with this screen object's
# number of colors
AttrSpec = lambda self, fg, bg: AttrSpec(fg, bg, self.colors)
-
+
def _test():
import doctest
diff -Nru urwid-1.2.1/urwid/signals.py urwid-1.3.0/urwid/signals.py
--- urwid-1.2.1/urwid/signals.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/signals.py 2014-10-17 20:09:04.000000000 +0200
@@ -150,8 +150,8 @@
sig_cls = obj.__class__
if not name in self._supported.get(sig_cls, []):
- raise NameError, "No such signal %r for object %r" % \
- (name, obj)
+ raise NameError("No such signal %r for object %r" %
+ (name, obj))
# Just generate an arbitrary (but unique) key
key = Key()
diff -Nru urwid-1.2.1/urwid/split_repr.py urwid-1.3.0/urwid/split_repr.py
--- urwid-1.2.1/urwid/split_repr.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/split_repr.py 2014-10-17 20:09:04.000000000 +0200
@@ -97,9 +97,9 @@
def remove_defaults(d, fn):
"""
Remove keys in d that are set to the default values from
- fn. This method is used to unclutter the _repr_attrs()
+ fn. This method is used to unclutter the _repr_attrs()
return value.
-
+
d will be modified by this function.
Returns d.
diff -Nru urwid-1.2.1/urwid/tests/test_event_loops.py urwid-1.3.0/urwid/tests/test_event_loops.py
--- urwid-1.2.1/urwid/tests/test_event_loops.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/tests/test_event_loops.py 2014-10-17 20:09:04.000000000 +0200
@@ -34,6 +34,8 @@
self.assertTrue(evl.remove_watch_file(handle))
self.assertFalse(evl.remove_watch_file(handle))
+ _expected_idle_handle = 1
+
def test_run(self):
evl = self.evl
out = []
@@ -50,10 +52,12 @@
1/0
handle = evl.alarm(0.01, exit_clean)
handle = evl.alarm(0.005, say_hello)
- self.assertEqual(evl.enter_idle(say_waiting), 1)
+ idle_handle = evl.enter_idle(say_waiting)
+ if self._expected_idle_handle is not None:
+ self.assertEqual(idle_handle, 1)
evl.run()
- self.assertIn("hello", out)
- self.assertIn("clean exit", out)
+ self.assertTrue("hello" in out, out)
+ self.assertTrue("clean exit"in out, out)
handle = evl.watch_file(rd, exit_clean)
del out[:]
evl.run()
@@ -125,7 +129,19 @@
handle = evl.alarm(0.005, say_hello)
self.assertEqual(evl.enter_idle(say_waiting), 1)
evl.run()
- self.assertIn("da", out)
- self.assertIn("ta", out)
- self.assertIn("hello", out)
- self.assertIn("clean exit", out)
+ self.assertTrue("da" in out, out)
+ self.assertTrue("ta" in out, out)
+ self.assertTrue("hello" in out, out)
+ self.assertTrue("clean exit" in out, out)
+
+
+try:
+ import asyncio
+except ImportError:
+ pass
+else:
+ class AsyncioEventLoopTest(unittest.TestCase, EventLoopTestMixin):
+ def setUp(self):
+ self.evl = urwid.AsyncioEventLoop()
+
+ _expected_idle_handle = None
diff -Nru urwid-1.2.1/urwid/text_layout.py urwid-1.3.0/urwid/text_layout.py
--- urwid-1.2.1/urwid/text_layout.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/text_layout.py 2014-10-17 20:09:04.000000000 +0200
@@ -97,7 +97,7 @@
if lw >= maxcol:
return maxcol
maxwidth = max(maxwidth, lw)
- return maxwidth
+ return maxwidth
def align_layout( self, text, width, segs, wrap, align ):
"""Convert the layout segs to an aligned layout."""
@@ -210,7 +210,7 @@
else:
# unwrap previous line space if possible to
# fit more text (we're breaking a word anyway)
- if b and (len(b[-1]) == 2 or ( len(b[-1])==1
+ if b and (len(b[-1]) == 2 or ( len(b[-1])==1
and len(b[-1][0])==2 )):
# look for removed space above
if len(b[-1]) == 1:
@@ -225,7 +225,7 @@
# combine with previous line
del b[-1]
p = p_off
- pos, sc = calc_text_pos(
+ pos, sc = calc_text_pos(
text, p, n_cr, width )
b.append([(sc,p,pos)])
# check for trailing " " or "\n"
@@ -250,18 +250,18 @@
default_layout = StandardTextLayout()
######################################
-
+
class LayoutSegment:
def __init__(self, seg):
"""Create object from line layout segment structure"""
-
+
assert type(seg) == tuple, repr(seg)
assert len(seg) in (2,3), repr(seg)
-
+
self.sc, self.offs = seg[:2]
-
+
assert type(self.sc) == int, repr(self.sc)
-
+
if len(seg)==3:
assert type(self.offs) == int, repr(self.offs)
assert self.sc > 0, repr(seg)
@@ -279,10 +279,10 @@
assert self.sc >= 0, repr(seg)
assert type(self.offs)==int
self.text = self.end = None
-
+
def subseg(self, text, start, end):
"""
- Return a "sub-segment" list containing segment structures
+ Return a "sub-segment" list containing segment structures
that make up a portion of this segment.
A list is returned to handle cases where wide characters
@@ -337,18 +337,18 @@
amount -- screen columns to shift right (+ve) or left (-ve)
"""
assert type(amount)==int, repr(amount)
-
+
if segs and len(segs[0])==2 and segs[0][1]==None:
# existing shift
amount += segs[0][0]
if amount:
return [(amount,None)]+segs[1:]
return segs[1:]
-
+
if amount:
return [(amount,None)]+segs
return segs
-
+
def trim_line( segs, text, start, end ):
"""
@@ -416,16 +416,16 @@
s = LayoutSegment(seg)
if s.offs is not None:
if s.end is not None:
- if (current_sc <= pref_col and
+ if (current_sc <= pref_col and
pref_col < current_sc + s.sc):
# exact match within this segment
- return calc_text_pos( text,
+ return calc_text_pos( text,
s.offs, s.end,
pref_col - current_sc )[0]
elif current_sc <= pref_col:
closest_sc = current_sc + s.sc - 1
closest_pos = s
-
+
if closest_sc is None or ( abs(pref_col-current_sc)
< abs(pref_col-closest_sc) ):
# this screen column is closer
@@ -435,7 +435,7 @@
# we're moving past
break
current_sc += s.sc
-
+
if closest_pos is None or type(closest_pos) == int:
return closest_pos
@@ -451,19 +451,19 @@
if row < 0 or row >= len(layout):
raise Exception("calculate_pos: out of layout row range")
-
+
pos = calc_line_pos( text, layout[row], pref_col )
if pos is not None:
return pos
-
+
rows_above = range(row-1,-1,-1)
rows_below = range(row+1,len(layout))
while rows_above and rows_below:
- if rows_above:
+ if rows_above:
r = rows_above.pop(0)
pos = calc_line_pos(text, layout[r], pref_col)
if pos is not None: return pos
- if rows_below:
+ if rows_below:
r = rows_below.pop(0)
pos = calc_line_pos(text, layout[r], pref_col)
if pos is not None: return pos
@@ -473,7 +473,7 @@
def calc_coords( text, layout, pos, clamp=1 ):
"""
Calculate the coordinates closest to position pos in text with layout.
-
+
text -- raw string or unicode string
layout -- layout structure applied to text
pos -- integer position into text
@@ -500,7 +500,7 @@
closest = distance, (x,y)
x += s.sc
y += 1
-
+
if closest:
return closest[1]
return 0,0
diff -Nru urwid-1.2.1/urwid/treetools.py urwid-1.3.0/urwid/treetools.py
--- urwid-1.2.1/urwid/treetools.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/treetools.py 2014-10-17 20:09:04.000000000 +0200
@@ -1,6 +1,6 @@
#!/usr/bin/python
#
-# Generic TreeWidget/TreeWalker class
+# Generic TreeWidget/TreeWalker class
# Copyright (c) 2010 Rob Lanphier
# Copyright (C) 2004-2010 Ian Ward
#
@@ -50,13 +50,13 @@
self.expanded = True
widget = self.get_indented_widget()
self.__super.__init__(widget)
-
+
def selectable(self):
"""
Allow selection of non-leaf nodes so children may be (un)expanded
"""
return not self.is_leaf
-
+
def get_indented_widget(self):
widget = self.get_inner_widget()
if not self.is_leaf:
@@ -64,9 +64,9 @@
[self.unexpanded_icon, self.expanded_icon][self.expanded]),
widget], dividechars=1)
indent_cols = self.get_indent_cols()
- return urwid.Padding(widget,
+ return urwid.Padding(widget,
width=('relative', 100), left=indent_cols)
-
+
def update_expanded_icon(self):
"""Update display widget text for parent widgets"""
# icon is first element in columns indented widget
@@ -83,12 +83,12 @@
def load_inner_widget(self):
return urwid.Text(self.get_display_text())
-
+
def get_node(self):
return self._node
def get_display_text(self):
- return (self.get_node().get_key() + ": " +
+ return (self.get_node().get_key() + ": " +
str(self.get_node().get_value()))
def next_inorder(self):
@@ -140,7 +140,7 @@
"""Handle expand & collapse requests (non-leaf nodes)"""
if self.is_leaf:
return key
-
+
if key in ("+", "right"):
self.expanded = True
self.update_expanded_icon()
@@ -151,7 +151,7 @@
return self.__super.keypress(size, key)
else:
return key
-
+
def mouse_event(self, size, event, button, col, row, focus):
if self.is_leaf or event != 'mouse press' or button!=1:
return False
@@ -160,12 +160,12 @@
self.expanded = not self.expanded
self.update_expanded_icon()
return True
-
+
return False
def first_child(self):
"""Return first child if expanded."""
- if self.is_leaf or not self.expanded:
+ if self.is_leaf or not self.expanded:
return None
else:
if self._node.has_children():
@@ -193,7 +193,7 @@
class TreeNode(object):
"""
- Store tree contents and cache TreeWidget objects.
+ Store tree contents and cache TreeWidget objects.
A TreeNode consists of the following elements:
* key: accessor token for parent nodes
* value: subclass-specific data
@@ -215,14 +215,14 @@
def load_widget(self):
return TreeWidget(self)
-
+
def get_depth(self):
if self._depth is None and self._parent is None:
self._depth = 0
elif self._depth is None:
self._depth = self._parent.get_depth() + 1
return self._depth
-
+
def get_index(self):
if self.get_depth() == 0:
return None
@@ -244,19 +244,19 @@
if self._parent == None and self.get_depth() > 0:
self._parent = self.load_parent()
return self._parent
-
+
def load_parent(self):
"""Provide TreeNode with a parent for the current node. This function
is only required if the tree was instantiated from a child node
(virtual function)"""
raise TreeWidgetError("virtual function. Implement in subclass")
-
+
def get_value(self):
return self._value
def is_root(self):
return self.get_depth() == 0
-
+
def next_sibling(self):
if self.get_depth() > 0:
return self.get_parent().next_child(self.get_key())
@@ -274,8 +274,8 @@
while root.get_parent() is not None:
root = root.get_parent()
return root
-
-
+
+
class ParentNode(TreeNode):
"""Maintain sort order for TreeNodes."""
def __init__(self, value, parent=None, key=None, depth=None):
@@ -297,7 +297,7 @@
def get_child_widget(self, key):
"""Return the widget for a given key. Create if necessary."""
-
+
child = self.get_child_node(key)
return child.get_widget()
@@ -312,10 +312,10 @@
raise TreeWidgetError("virtual function. Implement in subclass")
def set_child_node(self, key, node):
- """Set the child node for a given key. Useful for bottom-up, lazy
+ """Set the child node for a given key. Useful for bottom-up, lazy
population of a tree.."""
self._children[key]=node
-
+
def change_child_key(self, oldkey, newkey):
if newkey in self._children:
raise TreeWidgetError("%s is already in use" % newkey)
@@ -328,7 +328,7 @@
except ValueError:
errorstring = ("Can't find key %s in ParentNode %s\n" +
"ParentNode items: %s")
- raise TreeWidgetError(errorstring % (key, self.get_key(),
+ raise TreeWidgetError(errorstring % (key, self.get_key(),
str(self.get_child_keys())))
def next_child(self, key):
@@ -339,7 +339,7 @@
if index is None:
return None
index += 1
-
+
child_keys = self.get_child_keys()
if index < len(child_keys):
# get the next item at same level
@@ -355,7 +355,7 @@
child_keys = self.get_child_keys()
index -= 1
-
+
if index >= 0:
# get the previous item at same level
return self.get_child_node(child_keys[index])
@@ -366,12 +366,12 @@
"""Return the first TreeNode in the directory."""
child_keys = self.get_child_keys()
return self.get_child_node(child_keys[0])
-
+
def get_last_child(self):
"""Return the last TreeNode in the directory."""
child_keys = self.get_child_keys()
return self.get_child_node(child_keys[-1])
-
+
def has_children(self):
"""Does this node have any children?"""
return len(self.get_child_keys())>0
@@ -379,9 +379,9 @@
class TreeWalker(urwid.ListWalker):
"""ListWalker-compatible class for displaying TreeWidgets
-
+
positions are TreeNodes."""
-
+
def __init__(self, start_from):
"""start_from: TreeNode with the initial focus."""
self.focus = start_from
@@ -389,7 +389,7 @@
def get_focus(self):
widget = self.focus.get_widget()
return widget, self.focus
-
+
def set_focus(self, focus):
self.focus = focus
self._modified()
@@ -431,13 +431,13 @@
self.focus_end(size)
else:
return input
-
+
def collapse_focus_parent(self, size):
"""Collapse parent directory."""
widget, pos = self.body.get_focus()
self.move_focus_to_parent(size)
-
+
pwidget, ppos = self.body.get_focus()
if pos != ppos:
self.keypress(size, "-")
@@ -446,12 +446,12 @@
"""Move focus to parent of widget in focus."""
widget, pos = self.body.get_focus()
-
+
parentpos = pos.get_parent()
-
+
if parentpos is None:
return
-
+
middle, top, bottom = self.calculate_visible( size )
row_offset, focus_widget, focus_pos, focus_rows, cursor = middle
@@ -464,7 +464,7 @@
return
self.change_focus(size, pos.get_parent())
-
+
def focus_home(self, size):
"""Move focus to very top."""
diff -Nru urwid-1.2.1/urwid/util.py urwid-1.3.0/urwid/util.py
--- urwid-1.2.1/urwid/util.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/util.py 2014-10-17 20:09:04.000000000 +0200
@@ -45,7 +45,7 @@
except locale.Error:
pass
return locale.getlocale()[1] or ""
- except ValueError, e:
+ except ValueError as e:
# with invalid LANG value python will throw ValueError
if e.args and e.args[0].startswith("unknown locale"):
return ""
@@ -72,7 +72,7 @@
if encoding in ( 'utf-8', 'utf8', 'utf' ):
str_util.set_byte_encoding("utf8")
-
+
_use_dec_special = False
elif encoding in ( 'euc-jp' # JISX 0208 only
, 'euc-kr', 'euc-cn', 'euc-tw' # CNS 11643 plain 1 only
@@ -80,7 +80,7 @@
# these shouldn't happen, should they?
, 'eucjp', 'euckr', 'euccn', 'euctw', 'cncb' ):
str_util.set_byte_encoding("wide")
-
+
_use_dec_special = True
else:
str_util.set_byte_encoding("narrow")
@@ -88,7 +88,7 @@
# if encoding is valid for conversion from unicode, remember it
_target_encoding = 'ascii'
- try:
+ try:
if encoding:
u"".encode(encoding)
_target_encoding = encoding
@@ -114,7 +114,7 @@
s = s.translate( escape.DEC_SPECIAL_CHARMAP )
except NotImplementedError:
# python < 2.4 needs to do this the hard way..
- for c, alt in zip(escape.DEC_SPECIAL_CHARS,
+ for c, alt in zip(escape.DEC_SPECIAL_CHARS,
escape.ALT_DEC_SPECIAL_CHARS):
s = s.replace( c, escape.SO+alt+escape.SI )
@@ -136,10 +136,10 @@
if sis0:
sout.append( sis0 )
cout.append( (None,len(sis0)) )
-
+
if len(sis)==1:
return sis0, cout
-
+
for sn in sis[1:]:
assert isinstance(sn, bytes)
assert isinstance(SI, bytes)
@@ -200,7 +200,7 @@
spos, sc = calc_text_pos( text, spos, end_offs, start_col )
if sc < start_col:
pad_left = 1
- spos, sc = calc_text_pos( text, start_offs,
+ spos, sc = calc_text_pos( text, start_offs,
end_offs, start_col+1 )
run = end_col - start_col - pad_left
pos, sc = calc_text_pos( text, spos, end_offs, run )
@@ -215,7 +215,7 @@
"""
Return ( trimmed text, trimmed attr, trimmed cs ).
"""
- spos, epos, pad_left, pad_right = calc_trim_text(
+ spos, epos, pad_left, pad_right = calc_trim_text(
text, 0, len(text), start_col, end_col )
attrtr = rle_subseg( attr, spos, epos )
cstr = rle_subseg( cs, spos, epos )
@@ -263,7 +263,7 @@
break
if x+run > end:
run = end-x
- x += run
+ x += run
l.append( (a, run) )
return l
@@ -273,7 +273,7 @@
Return the number of characters covered by a run length
encoded attribute list.
"""
-
+
run = 0
for v in rle:
assert type(v) == tuple, repr(rle)
@@ -281,30 +281,32 @@
run += r
return run
-def rle_append_beginning_modify( rle, (a, r) ):
+def rle_append_beginning_modify(rle, a_r):
"""
- Append (a, r) to BEGINNING of rle.
+ Append (a, r) (unpacked from *a_r*) to BEGINNING of rle.
Merge with first run when possible
MODIFIES rle parameter contents. Returns None.
"""
+ a, r = a_r
if not rle:
rle[:] = [(a, r)]
- else:
+ else:
al, run = rle[0]
if a == al:
rle[0] = (a,run+r)
else:
rle[0:0] = [(al, r)]
-
-
-def rle_append_modify( rle, (a, r) ):
+
+
+def rle_append_modify(rle, a_r):
"""
- Append (a,r) to the rle list rle.
+ Append (a, r) (unpacked from *a_r*) to the rle list rle.
Merge with last run when possible.
-
+
MODIFIES rle parameter contents. Returns None.
"""
+ a, r = a_r
if not rle or rle[-1][0] != a:
rle.append( (a,r) )
return
@@ -322,7 +324,7 @@
return
rle_append_modify(rle, rle2[0])
rle += rle2[1:]
-
+
def rle_product( rle1, rle2 ):
"""
Merge the runs of rle1 and rle2 like this:
@@ -337,7 +339,7 @@
if not rle1 or not rle2: return []
a1, r1 = rle1[0]
a2, r2 = rle2[0]
-
+
l = []
while r1 and r2:
r = min(r1, r2)
@@ -350,7 +352,7 @@
if r2 == 0 and i2< len(rle2):
a2, r2 = rle2[i2]
i2 += 1
- return l
+ return l
def rle_factor( rle ):
@@ -381,13 +383,13 @@
def _tagmarkup_recurse( tm, attr ):
"""Return (text list, attribute list) for tagmarkup passed.
-
+
tm -- tagmarkup
attr -- current attribute or None"""
-
+
if type(tm) == list:
# for lists recurse to process each subelement
- rtl = []
+ rtl = []
ral = []
for element in tm:
tl, al = _tagmarkup_recurse( element, attr )
@@ -401,18 +403,18 @@
rtl += tl
ral += al
return rtl, ral
-
+
if type(tm) == tuple:
# tuples mark a new attribute boundary
- if len(tm) != 2:
- raise TagMarkupException, "Tuples must be in the form (attribute, tagmarkup): %r" % (tm,)
+ if len(tm) != 2:
+ raise TagMarkupException("Tuples must be in the form (attribute, tagmarkup): %r" % (tm,))
attr, element = tm
return _tagmarkup_recurse( element, attr )
-
+
if not isinstance(tm,(basestring, bytes)):
- raise TagMarkupException, "Invalid markup element: %r" % tm
-
+ raise TagMarkupException("Invalid markup element: %r" % tm)
+
# text
return [tm], [(attr, len(tm))]
@@ -431,15 +433,15 @@
def __init__(cls, name, bases, d):
super(MetaSuper, cls).__init__(name, bases, d)
if hasattr(cls, "_%s__super" % name):
- raise AttributeError, "Class has same name as one of its super classes"
+ raise AttributeError("Class has same name as one of its super classes")
setattr(cls, "_%s__super" % name, super(cls))
-
+
def int_scale(val, val_range, out_range):
"""
- Scale val in the range [0, val_range-1] to an integer in the range
- [0, out_range-1]. This implementation uses the "round-half-up" rounding
+ Scale val in the range [0, val_range-1] to an integer in the range
+ [0, out_range-1]. This implementation uses the "round-half-up" rounding
method.
>>> "%x" % int_scale(0x7, 0x10, 0x10000)
@@ -456,3 +458,17 @@
# if num % dem == 0 then we are exactly half-way and have rounded up.
return num // dem
+
+class StoppingContext(object):
+ """Context manager that calls ``stop`` on a given object on exit. Used to
+ make the ``start`` method on `MainLoop` and `BaseScreen` optionally act as
+ context managers.
+ """
+ def __init__(self, wrapped):
+ self._wrapped = wrapped
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *exc_info):
+ self._wrapped.stop()
diff -Nru urwid-1.2.1/urwid/version.py urwid-1.3.0/urwid/version.py
--- urwid-1.2.1/urwid/version.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/version.py 2014-10-17 20:09:04.000000000 +0200
@@ -1,5 +1,5 @@
-VERSION = (1, 2, 1)
+VERSION = (1, 3, 0)
__version__ = ''.join(['-.'[type(x) == int]+str(x) for x in VERSION])[1:]
diff -Nru urwid-1.2.1/urwid/vterm.py urwid-1.3.0/urwid/vterm.py
--- urwid-1.2.1/urwid/vterm.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/vterm.py 2014-10-17 20:09:04.000000000 +0200
@@ -22,18 +22,22 @@
import os
import sys
-import pty
import time
import copy
-import fcntl
import errno
import select
import struct
import signal
import atexit
-import termios
import traceback
+try:
+ import pty
+ import fcntl
+ import termios
+except ImportError:
+ pass # windows
+
from urwid import util
from urwid.escape import DEC_SPECIAL_CHARS, ALT_DEC_SPECIAL_CHARS
from urwid.canvas import Canvas
@@ -1518,7 +1522,7 @@
try:
select.select([self.master], [], [], timeout)
break
- except select.error, e:
+ except select.error as e:
if e.args[0] != 4:
raise
self.feed()
@@ -1528,7 +1532,7 @@
try:
data = os.read(self.master, 4096)
- except OSError, e:
+ except OSError as e:
if e.errno == 5: # End Of File
data = ''
elif e.errno == errno.EWOULDBLOCK: # empty buffer
diff -Nru urwid-1.2.1/urwid/web_display.py urwid-1.3.0/urwid/web_display.py
--- urwid-1.2.1/urwid/web_display.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/web_display.py 2014-10-17 20:09:04.000000000 +0200
@@ -77,8 +77,8 @@
33: "page up", 34: "page down", 35: "end", 36: "home",
37: "left", 38: "up", 39: "right", 40: "down",
45: "insert", 46: "delete",
- 112: "f1", 113: "f2", 114: "f3", 115: "f4",
- 116: "f5", 117: "f6", 118: "f7", 119: "f8",
+ 112: "f1", 113: "f2", 114: "f3", 115: "f4",
+ 116: "f5", 117: "f6", 118: "f7", 119: "f8",
120: "f9", 121: "f10", 122: "f11", 123: "f12"
};
@@ -179,16 +179,16 @@
urwid_id = conn.getResponseHeader("X-Urwid-ID");
if( send_queue_in != send_queue_out ){
// keys waiting
- do_send();
+ do_send();
}
if(update_method=="polling"){
set_status("Polling");
}else if(update_method=="multipart"){
set_status("Connected");
}
-
+
}
-
+
if( conn.responseText == "" ){
if(update_method=="polling"){
poll_again();
@@ -200,14 +200,14 @@
update_method = null;
return;
}
-
+
var text = document.getElementById('text');
-
+
var last_screen = Array(text.childNodes.length);
for( var i=0; i<text.childNodes.length; i++ ){
last_screen[i] = text.childNodes[i];
}
-
+
var frags = conn.responseText.split("\n");
var ln = document.createElement('span');
var k = 0;
@@ -244,7 +244,7 @@
for( var i=k; i < text.childNodes.length; i++ ){
text.removeChild(last_screen[i]);
}
-
+
if(update_method=="polling"){
poll_again();
}
@@ -263,17 +263,17 @@
}else{
document_location = document.location;
}
-
+
document.onkeypress = body_keypress;
document.onkeydown = body_keydown;
document.onresize = body_resize;
-
+
body_resize();
send_queue_out = send_queue_in; // don't queue the first resize
set_status("Connecting");
setup_connection();
-
+
setTimeout("check_fontsize();",check_font_delay);
}
@@ -288,7 +288,7 @@
d.style.backgroundColor = colours[bg];
d.style.color = colours[fg];
d.appendChild(document.createTextNode(s));
-
+
return d;
}
@@ -308,7 +308,7 @@
if( e.shiftKey && e.charCode == 0 ){ mod = "shift " + mod; }
key = keycodes[code];
-
+
if( key != undefined ){
lastkeydown = key;
send_key( mod + key );
@@ -332,7 +332,7 @@
if( e.ctrlKey ){ mod = "ctrl " + mod; }
if( e.altKey || e.metaKey ){ mod = "meta " + mod; }
if( e.shiftKey && e.charCode == 0 ){ mod = "shift " + mod; }
-
+
if( e.charCode != null && e.charCode != 0 ){
key = String.fromCharCode(e.charCode);
}else if( e.charCode == null ){
@@ -345,7 +345,7 @@
return false;
}
}
-
+
send_key( mod + key );
stop_key_event(e);
return false;
@@ -382,11 +382,11 @@
if( ! urwid_id ){ return; }
if( ! update_method ){ return; } // connection closed
if( send_queue_in == send_queue_out ){ return; }
- if( sending ){
+ if( sending ){
//var queue_delta = send_queue_in - send_queue_out;
//if( queue_delta < 0 ){ queue_delta += send_queue_max; }
- //set_status("Sending (queued "+queue_delta+")");
- return;
+ //set_status("Sending (queued "+queue_delta+")");
+ return;
}
try{
sending = true;
@@ -442,9 +442,9 @@
alert("Error from server: "+send_conn.statusText);
return;
}
-
+
sending = false;
-
+
if( send_queue_out != send_queue_in ){
send_more();
}
@@ -479,12 +479,12 @@
var avail_width = window_width-18;
var avail_width_mod = avail_width % char_width;
var x_size = (avail_width - avail_width_mod)/char_width;
-
+
char_height = t2.offsetTop - t.offsetTop;
var avail_height = window_height-text.offsetTop-10;
var avail_height_mod = avail_height % char_height;
var y_size = (avail_height - avail_height_mod)/char_height;
-
+
text.style.width = x_size*char_width+"px";
text.style.height = y_size*char_height+"px";
@@ -527,7 +527,7 @@
_trans_table = "?" * 32 + "".join([chr(x) for x in range(32, 256)])
_css_style = """
-body { margin: 8px 8px 8px 8px; border: 0;
+body { margin: 8px 8px 8px 8px; border: 0;
color: black; background-color: silver;
font-family: fixed; overflow: hidden; }
@@ -554,7 +554,7 @@
</head>
<body id="body" onload="load_web_display()">
<div style="position:absolute; visibility:hidden;">
-<br id="br"\>
+<br id="br"\>
<pre>The quick brown fox jumps over the lazy dog.<span id="testchar">X</span>
<span id="testchar2">Y</span></pre>
</div>
@@ -575,9 +575,9 @@
self.palette = {}
self.has_color = True
self._started = False
-
+
started = property(lambda self: self._started)
-
+
def register_palette( self, l ):
"""Register a list of palette entries.
@@ -586,18 +586,18 @@
calls self.register_palette_entry for each item in l
"""
-
+
for item in l:
if len(item) in (3,4):
self.register_palette_entry( *item )
continue
assert len(item) == 2, "Invalid register_palette usage"
name, like_name = item
- if not self.palette.has_key(like_name):
+ if like_name not in self.palette:
raise Exception("palette entry '%s' doesn't exist"%like_name)
self.palette[name] = self.palette[like_name]
- def register_palette_entry( self, name, foreground, background,
+ def register_palette_entry( self, name, foreground, background,
mono=None):
"""Register a single palette entry.
@@ -623,17 +623,18 @@
pass
def start(self):
- """
+ """
This function reads the initial screen size, generates a
unique id and handles cleanup when fn exits.
-
+
web_display.set_preferences(..) must be called before calling
this function for the preferences to take effect
"""
global _prefs
- assert not self._started
-
+ if self._started:
+ return util.StoppingContext(self)
+
client_init = sys.stdin.read(50)
assert client_init.startswith("window resize "),client_init
ignore1,ignore2,x,y = client_init.split(" ",3)
@@ -642,26 +643,26 @@
self._set_screen_size( x, y )
self.last_screen = {}
self.last_screen_width = 0
-
+
self.update_method = os.environ["HTTP_X_URWID_METHOD"]
assert self.update_method in ("multipart","polling")
-
+
if self.update_method == "polling" and not _prefs.allow_polling:
sys.stdout.write("Status: 403 Forbidden\r\n\r\n")
sys.exit(0)
-
+
clients = glob.glob(os.path.join(_prefs.pipe_dir,"urwid*.in"))
if len(clients) >= _prefs.max_clients:
sys.stdout.write("Status: 503 Sever Busy\r\n\r\n")
sys.exit(0)
-
+
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)
signal.signal(signal.SIGTERM,self._cleanup_pipe)
-
- self.input_fd = os.open(self.pipe_name+".in",
+
+ self.input_fd = os.open(self.pipe_name+".in",
os.O_NONBLOCK | os.O_RDONLY)
self.input_tail = ""
self.content_head = ("Content-type: "
@@ -674,16 +675,20 @@
"Content-type: text/plain\r\n"
"X-Urwid-ID: "+urwid_id+"\r\n"
"\r\n\r\n")
-
+
signal.signal(signal.SIGALRM,self._handle_alarm)
signal.alarm( ALARM_DELAY )
self._started = True
+ return util.StoppingContext(self)
+
def stop(self):
"""
- Restore settings and clean up.
+ Restore settings and clean up.
"""
- assert self._started
+ if not self._started:
+ return
+
# XXX which exceptions does this actually raise? EnvironmentError?
try:
self._close_connection()
@@ -692,7 +697,7 @@
signal.signal(signal.SIGTERM,signal.SIG_DFL)
self._cleanup_pipe()
self._started = False
-
+
def set_input_timeouts(self, *args):
pass
@@ -731,21 +736,21 @@
def _set_screen_size(self, cols, rows ):
"""Set the screen size (within max size)."""
-
+
if cols > MAX_COLS:
cols = MAX_COLS
if rows > MAX_ROWS:
rows = MAX_ROWS
self.screen_size = cols, rows
-
+
def draw_screen(self, (cols, rows), r ):
"""Send a screen update to the client."""
-
+
if cols != self.last_screen_width:
self.last_screen = {}
-
+
sendq = [self.content_head]
-
+
if self.update_method == "polling":
send = sendq.append
elif self.update_method == "polling child":
@@ -760,23 +765,23 @@
send = sendq.append
send("\r\n")
self.content_head = ""
-
+
assert r.rows() == rows
-
+
if r.cursor is not None:
cx, cy = r.cursor
else:
cx = cy = None
-
+
new_screen = {}
-
+
y = -1
for row in r.content():
y += 1
row = list(row)
-
+
l = []
-
+
sig = tuple(row)
if y == cy: sig = sig + (cx,)
new_screen[sig] = new_screen.get(sig,[]) + [y]
@@ -788,7 +793,7 @@
old_line = old_line_numbers[0]
send( "<%d\n"%old_line )
continue
-
+
col = 0
for (a, cs, run) in row:
run = run.translate(_trans_table)
@@ -797,7 +802,7 @@
else:
fg,bg,mono = self.palette[a]
if y == cy and col <= cx:
- run_width = util.calc_width(run, 0,
+ run_width = util.calc_width(run, 0,
len(run))
if col+run_width > cx:
l.append(code_span(run, fg, bg,
@@ -811,7 +816,7 @@
send("".join(l)+"\n")
self.last_screen = new_screen
self.last_screen_width = cols
-
+
if self.update_method == "polling":
sys.stdout.write("".join(sendq))
sys.stdout.flush()
@@ -823,9 +828,9 @@
send("\r\n--ZZ\r\n")
sys.stdout.write("".join(sendq))
sys.stdout.flush()
-
+
signal.alarm( ALARM_DELAY )
-
+
def clear(self):
"""
@@ -843,7 +848,7 @@
Force parent process to exit.
"""
daemonize( self.pipe_name +".err" )
- self.input_fd = os.open(self.pipe_name+".in",
+ self.input_fd = os.open(self.pipe_name+".in",
os.O_NONBLOCK | os.O_RDONLY)
self.update_method = "polling child"
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
@@ -851,7 +856,7 @@
s.listen(1)
s.settimeout(POLL_CONNECT)
self.server_socket = s
-
+
def _handle_alarm(self, sig, frame):
assert self.update_method in ("multipart","polling child")
if self.update_method == "polling child":
@@ -866,8 +871,8 @@
sys.stdout.write("\r\n\r\n--ZZ\r\n")
sys.stdout.flush()
signal.alarm( ALARM_DELAY )
-
-
+
+
def get_cols_rows(self):
"""Return the screen size."""
return self.screen_size
@@ -876,13 +881,13 @@
"""Return pending input as a list."""
l = []
resized = False
-
+
try:
iready,oready,eready = select.select(
[self.input_fd],[],[],0.5)
- except select.error, e:
+ except select.error as e:
# return on interruptions
- if e.args[0] == 4:
+ if e.args[0] == 4:
if raw_keys:
return [],[]
return []
@@ -892,16 +897,16 @@
if raw_keys:
return [],[]
return []
-
+
keydata = os.read(self.input_fd, MAX_READ)
os.close(self.input_fd)
- self.input_fd = os.open(self.pipe_name+".in",
+ self.input_fd = os.open(self.pipe_name+".in",
os.O_NONBLOCK | os.O_RDONLY)
#sys.stderr.write( repr((keydata,self.input_tail))+"\n" )
keys = keydata.split("\n")
keys[0] = self.input_tail + keys[0]
self.input_tail = keys[-1]
-
+
for k in keys[:-1]:
if k.startswith("window resize "):
ign1,ign2,x,y = k.split(" ",3)
@@ -913,16 +918,16 @@
l.append(k)
if resized:
l.append("window resize")
-
+
if raw_keys:
return l, []
return l
-
+
def code_span( s, fg, bg, cursor = -1):
code_fg = _code_colours[ fg ]
code_bg = _code_colours[ bg ]
-
+
if cursor >= 0:
c_off, _ign = util.calc_text_pos(s, 0, len(s), cursor)
c2_off = util.move_next_char(s, c_off, len(s))
@@ -941,12 +946,12 @@
text = text.replace('>','>')
return text
-
+
def is_web_request():
"""
Return True if this is a CGI web request.
"""
- return os.environ.has_key('REQUEST_METHOD')
+ return 'REQUEST_METHOD' in os.environ
def handle_short_request():
"""
@@ -959,21 +964,21 @@
function for the preferences to take effect
"""
global _prefs
-
+
if not is_web_request():
return False
-
+
if os.environ['REQUEST_METHOD'] == "GET":
# Initial request, send the HTML and javascript.
sys.stdout.write("Content-type: text/html\r\n\r\n" +
html_escape(_prefs.app_name).join(_html_page))
return True
-
+
if os.environ['REQUEST_METHOD'] != "POST":
# Don't know what to do with head requests etc.
return False
-
- if not os.environ.has_key('HTTP_X_URWID_ID'):
+
+ if 'HTTP_X_URWID_ID' not in os.environ:
# If no urwid id, then the application should be started.
return False
@@ -989,7 +994,7 @@
#assert 0, "invalid chars in id!"
sys.stdout.write("Status: 403 Forbidden\r\n\r\n")
return True
-
+
if os.environ.get('HTTP_X_URWID_METHOD',None) == "polling":
# this is a screen update request
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
@@ -1030,16 +1035,16 @@
_prefs = _Preferences()
-def set_preferences( app_name, pipe_dir="/tmp", allow_polling=True,
+def set_preferences( app_name, pipe_dir="/tmp", allow_polling=True,
max_clients=20 ):
"""
Set web_display preferences.
-
+
app_name -- application name to appear in html interface
- pipe_dir -- directory for input pipes, daemon update sockets
+ pipe_dir -- directory for input pipes, daemon update sockets
and daemon error logs
- allow_polling -- allow creation of daemon processes for
- browsers without multipart support
+ allow_polling -- allow creation of daemon processes for
+ browsers without multipart support
max_clients -- maximum concurrent client connections. This
pool is shared by all urwid applications
using the same pipe_dir
diff -Nru urwid-1.2.1/urwid/widget.py urwid-1.3.0/urwid/widget.py
--- urwid-1.2.1/urwid/widget.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/widget.py 2014-10-17 20:09:04.000000000 +0200
@@ -171,7 +171,7 @@
def nocache_widget_render_instance(self):
"""
Return a function that wraps the cls.render() method
- and finalizes the canvas that it returns, but does not
+ and finalizes the canvas that it returns, but does not
cache the canvas.
"""
fn = self.render.original_fn
@@ -852,10 +852,10 @@
def _repr_attrs(self):
attrs = dict(self.__super._repr_attrs(),
- align=self._align_mode,
+ align=self._align_mode,
wrap=self._wrap_mode)
return remove_defaults(attrs, Text.__init__)
-
+
def _invalidate(self):
self._cache_maxcol = None
self.__super._invalidate()
@@ -1497,7 +1497,7 @@
x,y = self.get_cursor_coords((maxcol,))
pref_col = self.get_pref_col((maxcol,))
assert pref_col is not None
- #if pref_col is None:
+ #if pref_col is None:
# pref_col = x
if self._command_map[key] == CURSOR_UP: y -= 1
@@ -1511,7 +1511,7 @@
if not self._delete_highlighted():
if p == 0: return key
p = move_prev_char(self.edit_text,0,p)
- self.set_edit_text( self.edit_text[:p] +
+ self.set_edit_text( self.edit_text[:p] +
self.edit_text[self.edit_pos:] )
self.set_edit_pos( p )
diff -Nru urwid-1.2.1/urwid/wimp.py urwid-1.3.0/urwid/wimp.py
--- urwid-1.2.1/urwid/wimp.py 2014-04-04 17:55:01.000000000 +0200
+++ urwid-1.3.0/urwid/wimp.py 2014-10-17 20:09:04.000000000 +0200
@@ -566,7 +566,7 @@
def create_pop_up(self):
"""
- Subclass must override this method and have is return a widget
+ Subclass must override this method and return a widget
to be used for the pop-up. This method is called once each time
the pop-up is opened.
"""
diff -Nru urwid-1.2.1/urwid.egg-info/PKG-INFO urwid-1.3.0/urwid.egg-info/PKG-INFO
--- urwid-1.2.1/urwid.egg-info/PKG-INFO 2014-04-04 17:55:41.000000000 +0200
+++ urwid-1.3.0/urwid.egg-info/PKG-INFO 2014-10-17 20:27:53.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: urwid
-Version: 1.2.1
+Version: 1.3.0
Summary: A full-featured console (xterm et al.) user interface library
Home-page: http://urwid.org/
Author: Ian Ward
diff -Nru urwid-1.2.1/urwid.egg-info/SOURCES.txt urwid-1.3.0/urwid.egg-info/SOURCES.txt
--- urwid-1.2.1/urwid.egg-info/SOURCES.txt 2014-04-04 17:55:41.000000000 +0200
+++ urwid-1.3.0/urwid.egg-info/SOURCES.txt 2014-10-17 20:27:53.000000000 +0200
@@ -152,6 +152,7 @@
docs/tutorial/smenu1.png
docs/tutorial/smenu2.png
docs/tutorial/smenu3.png
+examples/asyncio_socket_server.py
examples/bigtext.py
examples/browse.py
examples/calc.py
-------------- next part --------------
--- urwid-1.2.1/debian/changelog 2014-05-18 11:08:47.000000000 +0200
+++ urwid-1.3.0/debian/changelog 2015-09-16 11:57:47.000000000 +0200
@@ -1,3 +1,15 @@
+urwid (1.3.0-1) unstable; urgency=medium
+
+ * Team upload.
+ * Refactor rules file to use pybuild.
+ * Remove cdbs to build.
+ * New upstream release. (Closes: #789767)
+ * watch file: use pypi debian redirectory
+ * Bump compat level to 9
+ * Update standard version to 3.9.6, no changes required.
+
+ -- Gianfranco Costamagna <locutusofborg at debian.org> Tue, 15 Sep 2015 16:04:33 +0200
+
urwid (1.2.1-2) unstable; urgency=medium
* Team upload.
--- urwid-1.2.1/debian/compat 2014-04-04 18:49:51.000000000 +0200
+++ urwid-1.3.0/debian/compat 2015-09-16 11:57:09.000000000 +0200
@@ -1 +1 @@
-5
+9
--- urwid-1.2.1/debian/control 2014-04-04 19:08:58.000000000 +0200
+++ urwid-1.3.0/debian/control 2015-09-16 11:57:09.000000000 +0200
@@ -4,8 +4,7 @@
Maintainer: Debian Python Modules Team <python-modules-team at lists.alioth.debian.org>
Uploaders: Ian Ward <ian at excess.org>
Build-Depends:
- cdbs (>= 0.4.90~),
- debhelper (>= 5.0.37.2),
+ debhelper (>= 9),
python-all-dev (>= 2.6.6-3~),
python-gobject,
python-setuptools (>= 0.6.16),
@@ -13,7 +12,7 @@
python-twisted,
python3-all-dev (>= 3.2),
python3-setuptools
-Standards-Version: 3.9.5
+Standards-Version: 3.9.6
Homepage: http://excess.org/urwid/
Vcs-Svn: svn://anonscm.debian.org/python-modules/packages/urwid/trunk/
Vcs-Browser: http://anonscm.debian.org/viewvc/python-modules/packages/urwid/trunk/
--- urwid-1.2.1/debian/python3-urwid.install 2014-04-04 19:02:24.000000000 +0200
+++ urwid-1.3.0/debian/python3-urwid.install 1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-debian/tmp/usr/lib/python3*
--- urwid-1.2.1/debian/python-urwid.install 2014-04-04 19:02:24.000000000 +0200
+++ urwid-1.3.0/debian/python-urwid.install 1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-debian/tmp/usr/lib/python2*
--- urwid-1.2.1/debian/rules 2014-05-18 11:07:29.000000000 +0200
+++ urwid-1.3.0/debian/rules 2015-09-16 11:57:09.000000000 +0200
@@ -1,35 +1,10 @@
#!/usr/bin/make -f
-DEB_PYTHON_DISTUTILS_INSTALLDIR_SKEL=/usr/lib/@PYTHONBINARY@/dist-packages/
-DEB_PYTHON_INSTALL_ARGS_ALL=--prefix=/usr --no-compile -O0 --install-layout=deb
+export PYBUILD_NAME=urwid
-include /usr/share/cdbs/1/rules/debhelper.mk
-DEB_INSTALL_CHANGELOGS_ALL=docs/changelog.rst
-include /usr/share/cdbs/1/class/python-distutils.mk
+%:
+ dh $@ --with python2,python3 --buildsystem=pybuild
-build/python-urwid:: build-docs-test-stamp
-build-docs-test-stamp:
-ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
- set -e; for python in $(shell pyversions -r) $(shell py3versions -r); do \
- echo Testing with $$python; \
- $$python setup.py test; \
- done;
-else
- @echo "** tests disabled"
-endif
+override_dh_auto_build:
python setup.py build_sphinx
- touch build-docs-test-stamp
-
-install/python-urwid::
- chmod a+x debian/tmp/usr/lib/python*/dist-packages/urwid/*.py
- chmod a-x debian/tmp/usr/lib/python*/dist-packages/urwid/version.py
-
-install/python3-urwid::
- mv debian/tmp/usr/lib/$(shell py3versions -d) debian/tmp/usr/lib/python3
- -cp debian/tmp/usr/lib/python3.*/dist-packages/urwid/*.so debian/tmp/usr/lib/python3/dist-packages/urwid/
- rm -rf debian/tmp/usr/lib/python3.*
-
-clean::
- rm -rf build build-docs-test-stamp urwid.egg-info
- rm -f urwid/tests/test_vterm.py
- find . -name '*.so' -delete
+ dh_auto_build
--- urwid-1.2.1/debian/watch 2014-04-04 18:49:51.000000000 +0200
+++ urwid-1.3.0/debian/watch 2015-09-16 11:57:09.000000000 +0200
@@ -1,2 +1,3 @@
version=3
-http://pypi.python.org/packages/source/u/urwid/urwid-(.*).tar.gz
+opts=uversionmangle=s/(rc|a|b|c)/~$1/ \
+https://pypi.debian.net/urwid/urwid-(.+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))
More information about the Python-modules-team
mailing list