From 319a8283c7d9c14911cd26c5710a395942d86c32 Mon Sep 17 00:00:00 2001 From: Toshio Kuratomi Date: Thu, 21 Sep 2017 17:02:11 -0700 Subject: Initial python3 work This is enough to get presentty to display the demo presentation all the way through. The Python3 version appears to have some slight performance problems (or perhaps it's a difference in behaviour) during transitions. On displaying a new slide, the text pulses once (gets brighter than it should be in its final state). --- presentty/ansiparser.py | 3 +++ presentty/client.py | 2 ++ presentty/console.py | 13 ++++++--- presentty/image.py | 72 ++++++++++++++++++++++++++----------------------- presentty/palette.py | 2 ++ presentty/presentty.py | 17 +++++++----- presentty/rst.py | 36 +++++++++++++++---------- presentty/server.py | 10 ++++--- presentty/slide.py | 4 ++- presentty/text.py | 23 +++++++++------- presentty/transition.py | 30 ++++++++++++--------- 11 files changed, 129 insertions(+), 83 deletions(-) diff --git a/presentty/ansiparser.py b/presentty/ansiparser.py index 4750b9e..11d9de6 100644 --- a/presentty/ansiparser.py +++ b/presentty/ansiparser.py @@ -13,9 +13,12 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from __future__ import absolute_import, division, print_function + import re import urwid +from six.moves import range class ANSIParser(object): colors = [ diff --git a/presentty/client.py b/presentty/client.py index a819dfd..0df4a58 100644 --- a/presentty/client.py +++ b/presentty/client.py @@ -13,6 +13,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from __future__ import absolute_import, division, print_function + import socket class Client(object): diff --git a/presentty/console.py b/presentty/console.py index d10dc3e..35ddf4f 100644 --- a/presentty/console.py +++ b/presentty/console.py @@ -13,6 +13,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from __future__ import absolute_import, division, print_function + import argparse import sys import datetime @@ -20,10 +22,10 @@ import time import urwid -import palette -import client -import slide -import rst +from . import palette +from . import client +from . import slide +from . import rst PALETTE = [ ('reversed', 'standout', ''), @@ -166,8 +168,10 @@ class Screen(urwid.WidgetWrap): self.console.prev() elif key == 'page down': self.console.next() + #next(self.console) elif key == 'right': self.console.next() + #next(self.console) elif key == 'left': self.console.prev() elif key == 't': @@ -235,6 +239,7 @@ class Console(object): def next(self): self.screen.setCurrent(self.client.next()) + #self.screen.setCurrent(next(self.client)) def prev(self): self.screen.setCurrent(self.client.prev()) diff --git a/presentty/image.py b/presentty/image.py index 939536f..0fc700b 100644 --- a/presentty/image.py +++ b/presentty/image.py @@ -13,15 +13,21 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from __future__ import absolute_import, division, print_function + import subprocess -import HTMLParser import re import PIL import PIL.ExifTags import urwid -import slide +import six.moves.html_parser +from six.moves import range +from six.moves import input + +from . import slide + def nearest_color(x): if x < 0x30: return '0' @@ -36,7 +42,7 @@ class ANSIImage(urwid.Widget): super(ANSIImage, self).__init__() self.uri = uri image = self._loadImage() - self.htmlparser = HTMLParser.HTMLParser() + self.htmlparser = six.moves.html_parser.HTMLParser() self.ratio = float(image.size[0])/float(image.size[1]) self.hinter = hinter if scale > 1: @@ -89,12 +95,12 @@ class ANSIImage(urwid.Widget): def _blank(self, width, height): ret = [] for y in range(height): - ret.append("%s" % ('.'*width)) - return '
'.join(ret) + ret.append(b"%s" % (b'.'*width)) + return b'
'.join(ret) - SPAN_RE = re.compile(r"(.*)") + b_SPAN_RE = re.compile(br"(.*)") def render(self, size, focus=False): - spanre = self.SPAN_RE + b_spanre = self.b_SPAN_RE htmlparser = self.htmlparser # Calculate image size and any bounding box @@ -116,26 +122,26 @@ class ANSIImage(urwid.Widget): stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except OSError, e: + except OSError as e: if self._prime: if e.errno == 2: print("ERROR: jp2a is used but is not installed.") else: print("ERROR: unable to run jp2a: %s" % e) - raw_input("Press ENTER to continue.") - data = self._blank(width, height) + input("Press ENTER to continue.") + b_data = self._blank(width, height) else: image = self._loadImage() image = image.convert('RGBA') image.save(jp2a.stdin, 'JPEG') jp2a.stdin.close() - data = jp2a.stdout.read() + b_data = jp2a.stdout.read() jp2a.stderr.read() jp2a.wait() - line_list = [] + b_line_list = [] attr_list = [] - line_text = '' + b_line_text = b'' line_attrs = [] current_attr = [None, 0] current_fg = None @@ -144,28 +150,28 @@ class ANSIImage(urwid.Widget): # Top pad for padding in range(0, top_pad): - line_list.append(' ' * total_width) + b_line_list.append(b' ' * total_width) attr_list.append([(padding_attr, 1)] * total_width) - for line in data.split('
'): - if not line: + for b_line in b_data.split(b'
'): + if not b_line: continue # Left pad - line_text += ' ' * left_pad + b_line_text += b' ' * left_pad for fake_attr in range(0, left_pad): line_attrs.append((padding_attr, 1)) - for span in line.split('
'): + for b_span in b_line.split(b'
'): - if not span: + if not b_span: continue - m = spanre.match(span) - fg, bg, char = m.groups() - if '&' in char: - char = htmlparser.unescape(char) - char = char.encode('utf8') - line_text += char + m = b_spanre.match(b_span) + fg, bg, b_char = m.groups() + if b'&' in b_char: + char = htmlparser.unescape(b_char.decode('utf-8')) + b_char = char.encode('utf8') + b_line_text += b_char props = [] # TODO: if bold is set, append bold to props fg = ('#'+ @@ -177,13 +183,13 @@ class ANSIImage(urwid.Widget): nearest_color(int(bg[2:4], 16)) + nearest_color(int(bg[4:6], 16))) if current_fg == fg and current_bg == bg and current_props == props: - current_attr[1] += len(char) + current_attr[1] += len(b_char) else: if current_attr[0]: line_attrs.append(tuple(current_attr)) fg = ', '.join(props + [fg]) attr = urwid.AttrSpec(fg, bg) - current_attr = [attr, len(char)] + current_attr = [attr, len(b_char)] current_fg = fg current_bg = bg current_props = props @@ -193,21 +199,21 @@ class ANSIImage(urwid.Widget): current_bg = None # Right pad - line_text += ' ' * right_pad + b_line_text += b' ' * right_pad for fake_attr in range(0, right_pad): line_attrs.append((padding_attr, 1)) - line_list.append(line_text) - line_text = '' + b_line_list.append(b_line_text) + b_line_text = b'' attr_list.append(line_attrs) line_attrs = [] # Bottom pad for padding in range(0, bottom_pad): - line_list.append(' ' * total_width) + b_line_list.append(b' ' * total_width) attr_list.append([(padding_attr, 1)] * total_width) - canvas = urwid.TextCanvas(line_list, attr_list) + canvas = urwid.TextCanvas(b_line_list, attr_list) return canvas def main(): @@ -227,4 +233,4 @@ def main(): if True: with screen.start(): screen.draw_screen((80,25), fill.render((80,25))) - raw_input() + input() diff --git a/presentty/palette.py b/presentty/palette.py index 6079a95..534618f 100644 --- a/presentty/palette.py +++ b/presentty/palette.py @@ -13,6 +13,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from __future__ import absolute_import, division, print_function + import urwid DARK_PALETTE = { diff --git a/presentty/presentty.py b/presentty/presentty.py index d54d640..0b9cdac 100644 --- a/presentty/presentty.py +++ b/presentty/presentty.py @@ -13,17 +13,20 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from __future__ import absolute_import, division, print_function + import argparse import os import sys import time +import six import urwid -import slide -import server -import rst -import palette +from . import slide +from . import server +from . import rst +from . import palette class Presenter(object): @@ -152,11 +155,13 @@ def main(): plt = palette.DARK_PALETTE hinter = slide.ScreenHinter() parser = rst.PresentationParser(plt, hinter) - program = parser.parse(unicode(open(args.file).read(), 'utf-8'), args.file) + args_data = open(args.file, 'rb').read() + args_data = six.text_type(args_data, 'utf-8') + program = parser.parse(args_data, args.file) if args.warnings: w = parser.warnings.getvalue() if w: - print w + print(w) sys.exit(1) p = Presenter(plt) p.setProgram(program) diff --git a/presentty/rst.py b/presentty/rst.py index 5867ca1..e84b6df 100644 --- a/presentty/rst.py +++ b/presentty/rst.py @@ -13,21 +13,26 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from __future__ import absolute_import, division, print_function + import os import re import docutils import docutils.frontend import docutils.parsers.rst import docutils.nodes -import cStringIO as StringIO +from io import StringIO +import six +from six.moves import range +from six.moves import input import urwid -import slide -import transition as transition_mod -import image -import ansiparser -import text +from . import slide +from . import transition as transition_mod +from . import image +from . import ansiparser +from . import text try: import PIL @@ -327,7 +332,8 @@ class UrwidTranslator(docutils.nodes.GenericNodeVisitor): for name in node['names']: p = ansiparser.ANSIParser() fn = os.path.join(self.basedir, name) - data = unicode(open(fn).read(), 'utf8') + data = open(fn, 'rb').read() + data = six.text_type(data, 'utf-8') text = p.parse(data) animation.addFrame(text) self.slide.animations.append(animation) @@ -447,7 +453,7 @@ class PresentationParser(object): 'cowsay', CowsayDirective) docutils.parsers.rst.directives.register_directive( 'hidetitle', HideTitleDirective) - self.warnings = StringIO.StringIO() + self.warnings = StringIO() self.settings = docutils.frontend.OptionParser( components=(docutils.parsers.rst.Parser,), defaults=dict(warning_stream=self.warnings)).get_default_values() @@ -469,7 +475,7 @@ class PresentationParser(object): def main(): import argparse - import palette + from . import palette argp = argparse.ArgumentParser(description='Test RST parser') argp.add_argument('file', help='presentation file (RST)') @@ -480,7 +486,9 @@ def main(): args = argp.parse_args() parser = PresentationParser(palette.DARK_PALETTE) - document, visitor = parser._parse(unicode(open(args.file).read(), 'utf-8'), args.file) + args_data = open(args.file, 'rb').read() + args_data = six.text_type(args_data, 'utf-8') + document, visitor = parser._parse(args_data, args.file) slides = args.slides if not slides: @@ -488,19 +496,19 @@ def main(): slides = [int(x) for x in slides] if not args.render: - print document.pformat() + print(document.pformat()) for i in slides: - print '-'*80 + print('-'*80) s = visitor.program[i] for line in s.render((80,25)).text: - print line + print(line) else: screen = urwid.raw_display.Screen() with screen.start(): for i in slides: s = visitor.program[i] screen.draw_screen((80,25), s.render((80,25))) - raw_input() + input() if __name__ == '__main__': main() diff --git a/presentty/server.py b/presentty/server.py index 74e64b2..ad4c441 100644 --- a/presentty/server.py +++ b/presentty/server.py @@ -13,11 +13,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from __future__ import absolute_import, division, print_function + import os import threading -import SocketServer -class ConsoleHandler(SocketServer.StreamRequestHandler): +import six.moves.socketserver + +class ConsoleHandler(six.moves.socketserver.StreamRequestHandler): def handle(self): server = self.server.server while True: @@ -38,6 +41,7 @@ class ConsoleHandler(SocketServer.StreamRequestHandler): i, slide.progressive_state, slide.title)) elif data == 'next': i, slide = server.next() + #i, slide = next(server) self.wfile.write('current %i %i %s\n' % ( i, slide.progressive_state, slide.title)) elif data == 'prev': @@ -53,7 +57,7 @@ class ConsoleHandler(SocketServer.StreamRequestHandler): size = server.size() self.wfile.write('size %s %s\n' % size) -class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): +class ThreadedTCPServer(six.moves.socketserver.ThreadingMixIn, six.moves.socketserver.TCPServer): allow_reuse_address=True class ConsoleServer(object): diff --git a/presentty/slide.py b/presentty/slide.py index 4894f45..ba6726c 100644 --- a/presentty/slide.py +++ b/presentty/slide.py @@ -13,6 +13,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from __future__ import absolute_import, division, print_function + import urwid class SlidePile(urwid.Pile): @@ -29,7 +31,7 @@ class SlidePile(urwid.Pile): class SlidePadding(urwid.Padding): def pack(self, size, focus=False): r = self._original_widget.pack(size, focus) - width = max(r[0] + self.left + self.right, self.min_width) + width = max(r[0] + self.left + self.right, self.min_width or 0) width = min(size[0], width) return (width, r[1]) diff --git a/presentty/text.py b/presentty/text.py index 92c0a26..37c3316 100644 --- a/presentty/text.py +++ b/presentty/text.py @@ -13,9 +13,12 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from __future__ import absolute_import, division, print_function + import subprocess import urwid +from six.moves import input class FigletText(urwid.WidgetWrap): def __init__(self, text, attr=None): @@ -34,17 +37,17 @@ class FigletText(urwid.WidgetWrap): stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except OSError, e: + except OSError as e: if e.errno == 2: print("ERROR: figlet is used but is not installed.") else: print("ERROR: unable to run figlet: %s" % e) - raw_input("Press ENTER to continue.") + input("Press ENTER to continue.") data = "[Unable to run figlet]" else: - p.stdin.write(self.text) + p.stdin.write(self.text.encode('utf-8')) p.stdin.close() - data = p.stdout.read() + data = p.stdout.read().decode('utf-8') p.stderr.read() p.wait() return data @@ -66,23 +69,23 @@ class CowsayText(urwid.WidgetWrap): stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except OSError, e: + except OSError as e: if e.errno == 2: print("ERROR: cowsay is used but is not installed.") else: print("ERROR: unable to run cowsay: %s" % e) - raw_input("Press ENTER to continue.") + input("Press ENTER to continue.") data = "[Unable to run cowsay]" else: - p.stdin.write(self.text) + p.stdin.write(self.text.encode('utf-8')) p.stdin.close() - data = p.stdout.read() + data = p.stdout.read().decode('utf-8') p.stderr.read() p.wait() return data def main(): - import slide + from . import slide w = FigletText("Testing") slpile = slide.SlidePile([]) slpile.contents.append((w, slpile.options())) @@ -94,6 +97,6 @@ def main(): if True: with screen.start(): screen.draw_screen((80,25), fill.render((80,25))) - raw_input() + input() if __name__=='__main__': main() diff --git a/presentty/transition.py b/presentty/transition.py index 5592cd9..1e9fbad 100644 --- a/presentty/transition.py +++ b/presentty/transition.py @@ -13,7 +13,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from __future__ import absolute_import, division, print_function + +import six import urwid +from six.moves import range class Transition(urwid.Widget): def __init__(self, duration=0.4): @@ -76,7 +80,9 @@ class DissolveTransition(Transition): buf = [] for line in canvas.content(): for (attr, cs, text) in line: - for char in unicode(text, 'utf8'): + if not isinstance(text, six.text_type): + text = six.text_type(text, 'utf-8') + for char in text: buf.append((attr, cs, char)) return buf @@ -87,9 +93,9 @@ class DissolveTransition(Transition): self._oldbuf = self._to_buf(old) self._newbuf = self._to_buf(new) self._cache_size = size - line_list = [] + b_line_list = [] attr_list = [] - line_text = '' + b_line_text = b'' line_attrs = [] current_attr = [None, 0] current_rgb = None @@ -104,11 +110,11 @@ class DissolveTransition(Transition): oldrgb = background.get_rgb_values() if None in newrgb: newrgb = background.get_rgb_values() - if newchar == ' ': + if newchar == b' ': char = oldchar charattr = oldattr newrgb = newrgb[3:]*2 - elif oldchar == ' ': + elif oldchar == b' ': char = newchar charattr = newattr oldrgb = oldrgb[3:]*2 @@ -118,8 +124,8 @@ class DissolveTransition(Transition): else: char = oldchar charattr = oldattr - char = char.encode('utf8') - line_text += char + b_char = char.encode('utf8') + b_line_text += b_char rgb = [] props = [] if charattr.bold: @@ -133,25 +139,25 @@ class DissolveTransition(Transition): for x in range(len(oldrgb)): rgb.append(int(((newrgb[x]-oldrgb[x])*self.progress)+oldrgb[x])>>4) if current_rgb == rgb and current_props == props: - current_attr[1] += len(char) + current_attr[1] += len(b_char) else: if current_attr[0]: line_attrs.append(tuple(current_attr)) fg = ', '.join(props + ['#%x%x%x' % tuple(rgb[:3])]) bg = '#%x%x%x' % tuple(rgb[3:]) attr = urwid.AttrSpec(fg, bg) - current_attr = [attr, len(char)] + current_attr = [attr, len(b_char)] current_rgb = rgb current_props = props if (i+1) % size[0] == 0: line_attrs.append(tuple(current_attr)) current_attr = [None, 0] current_rgb = None - line_list.append(line_text) - line_text = '' + b_line_list.append(b_line_text) + b_line_text = b'' attr_list.append(line_attrs) line_attrs = [] - canvas = urwid.TextCanvas(line_list, attr_list) + canvas = urwid.TextCanvas(b_line_list, attr_list) return canvas class CutTransition(Transition): -- cgit