Initial port to Python 3
authorJack Miller <jack@codezen.org>
Tue, 7 Feb 2012 21:00:12 +0000 (15:00 -0600)
committerJack Miller <jack@codezen.org>
Tue, 7 Feb 2012 21:00:12 +0000 (15:00 -0600)
Could be some lingering issues.

Signed-off-by: Jack Miller <jack@codezen.org>
34 files changed:
canto_curses/command.py
canto_curses/gui.py
canto_curses/guibase.py
canto_curses/html.py
canto_curses/input.py
canto_curses/main.py
canto_curses/parser.py
canto_curses/reader.py
canto_curses/screen.py
canto_curses/story.py
canto_curses/tag.py
canto_curses/taglist.py
canto_curses/text.py
canto_curses/theme.py
canto_curses/widecurse.c
tests/README [deleted file]
tests/addfeed/skel/canto-addfeed.xml [deleted file]
tests/addfeed/skel/conf [deleted file]
tests/addfeed/skel/expected.gz [deleted file]
tests/addfeed/skel/feeds [deleted file]
tests/addfeed/skel/script.sh [deleted file]
tests/baseline/skel/conf [deleted file]
tests/baseline/skel/expected.gz [deleted file]
tests/baseline/skel/feeds [deleted file]
tests/baseline/skel/script.sh [deleted file]
tests/delfeed/skel/conf [deleted file]
tests/delfeed/skel/expected.gz [deleted file]
tests/delfeed/skel/feeds [deleted file]
tests/delfeed/skel/script.sh [deleted file]
tests/enum_height/skel/conf [deleted file]
tests/enum_height/skel/expected.gz [deleted file]
tests/enum_height/skel/feeds [deleted file]
tests/enum_height/skel/script.sh [deleted file]
tests/run.sh [deleted file]

index 3a29b14..8579934 100644 (file)
@@ -7,7 +7,6 @@
 #   published by the Free Software Foundation.
 
 from canto_next.plugins import PluginHandler, Plugin, add_arg_transform
-from canto_next.encoding import encoder, decoder
 
 import traceback
 import logging
@@ -77,7 +76,7 @@ class CommandHandler(PluginHandler):
                 if r == None:
                     return True
                 return r
-            except Exception, e:
+            except Exception as e:
                 tb = traceback.format_exc(e)
                 log.error("Exception running command %s" % command)
                 log.error("\n" + "".join(tb))
@@ -188,7 +187,7 @@ class CommandHandler(PluginHandler):
             args = prompt()
 
         if args == "*" and maxint:
-            return range(0, maxint)
+            return list(range(0, maxint))
 
         if " " in args:
             terms = args.split(" ")
@@ -208,9 +207,9 @@ class CommandHandler(PluginHandler):
                     log.error("Can't parse %s as range" % term)
                     continue
                 if maxint:
-                    r.extend(range(min(a, maxint), min(b + 1, maxint)))
+                    r.extend(list(range(min(a, maxint), min(b + 1, maxint))))
                 else:
-                    r.extend(range(a, b + 1))
+                    r.extend(list(range(a, b + 1)))
             else:
                 try:
                     term = self._convert_special(term, curint, maxint)
@@ -251,7 +250,7 @@ class CommandHandler(PluginHandler):
         if not args:
             args = prompt()
 
-        r = [ decoder(s) for s in shlex.split(encoder(args)) ]
+        r = shlex.split(args)
 
         # I wish shlex.split took a max so I didn't have to zip them up
         # again with pipes.quote.
index aef6588..a579a81 100644 (file)
@@ -11,16 +11,15 @@ COMPATIBLE_VERSION = 0.3
 from canto_next.hooks import call_hook, on_hook
 from canto_next.plugins import Plugin
 from canto_next.remote import assign_to_dict, access_dict
-from canto_next.encoding import decoder
 from canto_next.format import escsplit
 
-from command import CommandHandler, command_format
-from story import DEFAULT_FSTRING
-from text import ErrorBox, InfoBox
-from screen import Screen, color_translate
-from tag import Tag, DEFAULT_TAG_FSTRING
+from .command import CommandHandler, command_format
+from .story import DEFAULT_FSTRING
+from .text import ErrorBox, InfoBox
+from .screen import Screen, color_translate
+from .tag import Tag, DEFAULT_TAG_FSTRING
 
-from Queue import Empty
+from queue import Empty
 import logging
 import curses
 import pprint
@@ -427,13 +426,13 @@ Until reconnected, it will be impossible to fetch any information, and any state
 
         # Make sure that we're not mismatching versions.
 
-        self.write("VERSION", u"")
+        self.write("VERSION", "")
         r = self.wait_response("VERSION")
         if r[1] != COMPATIBLE_VERSION:
             s = "Incompatible daemon version (%s) detected! Expected: %s" %\
                 (r[1], COMPATIBLE_VERSION)
             log.debug(s)
-            print s
+            print(s)
             sys.exit(-1)
         else:
             log.debug("Got compatible daemon version.")
@@ -442,12 +441,12 @@ Until reconnected, it will be impossible to fetch any information, and any state
         self.write("WATCHNEWTAGS", [])
         self.write("WATCHDELTAGS", [])
 
-        self.write("LISTTAGS", u"")
+        self.write("LISTTAGS", "")
         r = self.wait_response("LISTTAGS")
 
         self.stub_tagconfigs(r[1])
 
-        self.write("WATCHCONFIGS", u"")
+        self.write("WATCHCONFIGS", "")
         self.write("CONFIGS", [])
         self.prot_configs(self.wait_response("CONFIGS")[1])
 
@@ -520,10 +519,8 @@ Until reconnected, it will be impossible to fetch any information, and any state
         return (False, False)
 
     def validate_string(self, val, d):
-        if type(val) == unicode:
-            return (True, val)
         if type(val) == str:
-            return (True, decoder(val))
+            return (True, val)
         return (False, False)
 
     def validate_bool(self, val, d):
@@ -532,7 +529,7 @@ Until reconnected, it will be impossible to fetch any information, and any state
         return (False, False)
 
     def validate_update_style(self, val, d):
-        if val in [ u"maintain", u"append" ]:
+        if val in [ "maintain", "append" ]:
             return (True, val)
         return (False, False)
 
@@ -605,28 +602,19 @@ Until reconnected, it will be impossible to fetch any information, and any state
         if type(val) != dict:
             return (False, False)
 
-        for key in val.keys():
-            if type(key) != unicode:
-                if type(key) == str:
-                    newkey = decoder(key)
-                    v = val[key]
-                    del val[key]
-                    val[newkey] = v
-                else:
-                    return (False, False)
+        for key in list(val.keys()):
+            if type(key) != str:
+                return (False, False)
 
-            if type(val[key]) != unicode:
-                if type(val[key]) == str:
-                    val[key] = decoder(val[key])
-                else:
-                    return (False, False)
+            if type(val[key]) != str:
+                return (False, False)
 
         # For keys, because we don't want to specify each and every possible
         # key explicitly, so we merge in default keys. If a user wants to
         # ignore a default key, he can set it to None and it won't be merged
         # over.
 
-        for key in d.keys():
+        for key in list(d.keys()):
             if key not in val:
                 val[key] = d[key]
 
@@ -656,7 +644,7 @@ Until reconnected, it will be impossible to fetch any information, and any state
             return (True, r)
 
         # We have no idea what to do with this crap...
-        if type(val) not in [ unicode, str ]:
+        if type(val) != str:
             return (False, False)
 
         # See if it's an integer as a string
@@ -674,10 +662,8 @@ Until reconnected, it will be impossible to fetch any information, and any state
 
         r = []
         for item in val:
-            if type(item) == unicode:
+            if type(item) == str:
                 r.append(item)
-            elif type(item) == str:
-                r.append(decoder(item))
             else:
                 return (False, False)
 
@@ -712,13 +698,13 @@ Until reconnected, it will be impossible to fetch any information, and any state
 
         log.debug("d = %s" % d)
 
-        for key in v.keys():
+        for key in list(v.keys()):
             if key not in c:
                 c[key] = d[key]
 
         # Validate existing values.
 
-        for key in c.keys():
+        for key in list(c.keys()):
 
             # Unknown values, don't validate
             if key not in v:
@@ -768,7 +754,7 @@ Until reconnected, it will be impossible to fetch any information, and any state
         log.debug("prot_configs given: %s" % given)
 
         if "tags" in given:
-            for tag in given["tags"].keys():
+            for tag in list(given["tags"].keys()):
                 ntc = given["tags"][tag]
                 tc = self.tag_config[tag]
 
@@ -811,11 +797,8 @@ Until reconnected, it will be impossible to fetch any information, and any state
                     continue
 
                 for k in d[given_id]:
-                    if type(d[given_id][k]) == str:
-                        item.content[k] = decoder(d[given_id][k])
-                    else:
-                        item.content[k] = d[given_id][k]
-                atts[item] = d[given_id].keys()
+                    item.content[k] = d[given_id][k]
+                atts[item.id] = list(d[given_id].keys())
         if atts:
             call_hook("attributes", [ atts ])
 
@@ -940,7 +923,7 @@ Until reconnected, it will be impossible to fetch any information, and any state
         log.error("%s" % exception)
 
     def prot_errors(self, errors):
-        for key in errors.keys():
+        for key in list(errors.keys()):
             val = errors[key][1][0]
             symptom = errors[key][1][1]
             log.error("%s = %s : %s" % (key, val, symptom))
index 8c8efd8..4d9483f 100644 (file)
@@ -7,10 +7,10 @@
 #   published by the Free Software Foundation.
 
 from canto_next.hooks import call_hook, on_hook
-from canto_next.encoding import encoder, decoder
+from canto_next.encoding import encoder
 from canto_next.plugins import Plugin
 
-from command import CommandHandler, command_format
+from .command import CommandHandler, command_format
 
 import logging
 
@@ -18,7 +18,7 @@ log = logging.getLogger("COMMON")
 
 import subprocess
 import tempfile
-import urllib2
+import urllib.request, urllib.error, urllib.parse
 import shlex
 import sys
 import os
@@ -112,7 +112,7 @@ class GuiBase(CommandHandler):
             tmp = open(tmpnam, 'w+b')
 
             # Grab the HTTP info / prepare to read.
-            response = urllib2.urlopen(href)
+            response = urllib.request.urlopen(href)
 
             # Grab in kilobyte chunks to avoid wasting memory on something
             # that's going to be immediately written to disk.
@@ -199,8 +199,7 @@ class GuiBase(CommandHandler):
         if not args:
             args = prompt()
 
-        r = [ decoder(s) for s in shlex.split(encoder(args)) ]
-        return (True, r, None)
+        return (True, shlex.split(args), None)
 
     def one_opt(self, args):
         t, r = self._first_term(args,
@@ -227,7 +226,8 @@ class GuiBase(CommandHandler):
 
         log.debug("Calling remote: %s" % argv)
 
-        out = decoder(subprocess.check_output(argv))
+        # check_output return bytes, we must decode.
+        out = subprocess.check_output(argv).decode()
 
         log.debug("Output:")
         log.debug(out)
index 174d1df..0d1d0b4 100644 (file)
@@ -6,8 +6,8 @@
 #   it under the terms of the GNU General Public License version 2 as 
 #   published by the Free Software Foundation.
 
-from HTMLParser import HTMLParser
-import htmlentitydefs
+from html.parser import HTMLParser
+import html.entities
 import re
 
 import logging
@@ -41,7 +41,7 @@ class CantoHTML(HTMLParser):
 
     def handle_data(self, text):
         if self.verbatim <= 0:
-            text = text.replace(u"\n", u" ")
+            text = text.replace("\n", " ")
 
         if self.link_open:
             log.debug("adding %s to link_text" % text)
@@ -51,21 +51,21 @@ class CantoHTML(HTMLParser):
 
     def convert_charref(self, ref):
         try:
-            if ref[0] in [u'x',u'X']:
+            if ref[0] in ['x','X']:
                 c = int(ref[1:], 16)
             else:
                 c = int(ref)
         except:
-            return u"[?]"
-        return unichr(c)
+            return "[?]"
+        return chr(c)
 
     def handle_charref(self, ref):
         self.result += self.convert_charref(ref)
 
     def convert_entityref(self, ref):
-        if ref in htmlentitydefs.name2codepoint:
-            return unichr(htmlentitydefs.name2codepoint[ref])
-        return u"[?]"
+        if ref in html.entities.name2codepoint:
+            return chr(html.entities.name2codepoint[ref])
+        return "[?]"
 
     def handle_entityref(self, ref):
         self.result += self.convert_entityref(ref)
@@ -94,7 +94,7 @@ class CantoHTML(HTMLParser):
                 self.link_text = ""
                 self.link_href = ""
                 self.link_open = False
-                self.result += "[" + unicode(len(self.links)) + "]%0"
+                self.result += "[" + str(len(self.links)) + "]%0"
 
         elif tag in ["img"]:
             if open:
@@ -104,67 +104,67 @@ class CantoHTML(HTMLParser):
                     attrs["alt"] = ""
                 self.links.append(("image", attrs["src"], attrs["alt"]))
                 self.handle_data("%4" + attrs["alt"] +\
-                        "[" + unicode(len(self.links)) + "]%0")
+                        "[" + str(len(self.links)) + "]%0")
 
-        elif tag in [u"h" + unicode(x) for x in xrange(1,7)]:
+        elif tag in ["h" + str(x) for x in range(1,7)]:
             if open:
-                self.result += u"\n%B"
+                self.result += "\n%B"
             else:
-                self.result += u"%b\n"
-        elif tag in [u"blockquote"]:
+                self.result += "%b\n"
+        elif tag in ["blockquote"]:
             if open:
-                self.result += u"\n%Q"
+                self.result += "\n%Q"
             else:
-                self.result += u"%q\n"
-        elif tag in [u"pre",u"code"]:
+                self.result += "%q\n"
+        elif tag in ["pre","code"]:
             if open:
-                if tag == u"pre":
-                    self.result += u"\n%Q"
+                if tag == "pre":
+                    self.result += "\n%Q"
                 self.verbatim += 1
             else:
-                if tag == u"pre":
-                    self.result += u"%q\n"
+                if tag == "pre":
+                    self.result += "%q\n"
                 self.verbatim -= 1
-        elif tag in [u"sup"]:
+        elif tag in ["sup"]:
             if open:
-                self.result += u"^"
-        elif tag in [u"p", u"br", u"div"]:
-            self.result += u"\n"
-        elif tag in [u"ul", u"ol"]:
+                self.result += "^"
+        elif tag in ["p", "br", "div"]:
+            self.result += "\n"
+        elif tag in ["ul", "ol"]:
             if open:
-                self.result += u"\n%I"
+                self.result += "\n%I"
                 self.list_stack.append([tag,0])
             else:
                 # Grumble grumble. Bad HTML.
                 if len(self.list_stack):
                     self.list_stack.pop()
-                self.result += u"%i\n"
-        elif tag in [u"li"]:
+                self.result += "%i\n"
+        elif tag in ["li"]:
             if open:
-                self.result += u"\n"
+                self.result += "\n"
 
                 # List item with no start tag, default to ul
                 if not len(self.list_stack):
                     self.list_stack.append(["ul",0])
 
-                if self.list_stack[-1][0] == u"ul":
-                    self.result += u"\u25CF "
+                if self.list_stack[-1][0] == "ul":
+                    self.result += "\u25CF "
                 else:
                     self.list_stack[-1][1] += 1
-                    self.result += unicode(self.list_stack[-1][1])+ ". "
+                    self.result += str(self.list_stack[-1][1])+ ". "
             else:
-                self.result += u"\n"
+                self.result += "\n"
 
-        elif tag in [u"i", u"small", u"em"]:
+        elif tag in ["i", "small", "em"]:
             if open:
-                self.result += u"%6%B"
+                self.result += "%6%B"
             else:
-                self.result += u"%b%0"
-        elif tag in [u"b", u"strong"]:
+                self.result += "%b%0"
+        elif tag in ["b", "strong"]:
             if open:
-                self.result += u"%B"
+                self.result += "%B"
             else:
-                self.result += u"%b"
+                self.result += "%b"
 
     def ent_wrapper(self, match):
         return self.convert_entityref(match.groups()[0])
@@ -188,12 +188,12 @@ class CantoHTML(HTMLParser):
 
 htmlparser = CantoHTML()
 
-html_entity_regex = re.compile(u"&(\w{1,8});")
+html_entity_regex = re.compile("&(\w{1,8});")
 
 def html_entity_convert(s):
     return html_entity_regex.sub(htmlparser.ent_wrapper, s)
 
-char_ref_regex = re.compile(u"&#([xX]?[0-9a-fA-F]+)[^0-9a-fA-F]")
+char_ref_regex = re.compile("&#([xX]?[0-9a-fA-F]+)[^0-9a-fA-F]")
 
 def char_ref_convert(s):
     return char_ref_regex.sub(htmlparser.char_wrapper, s)
index fb0606b..4719c72 100644 (file)
@@ -25,7 +25,7 @@
 
 from canto_next.encoding import encoder
 from canto_next.plugins import Plugin
-from guibase import GuiBase
+from .guibase import GuiBase
 
 import logging
 log = logging.getLogger("INPUT")
@@ -100,7 +100,7 @@ class InputBox(GuiBase):
             return 0
         else:
             idx = self.x - self.minx
-            self.result = self.result[:idx] + unichr(ch) + self.result[idx:]
+            self.result = self.result[:idx] + chr(ch) + self.result[idx:]
             self.x += 1
 
         self.refresh()
index de1fa62..7e2a897 100644 (file)
@@ -7,13 +7,12 @@
 #   published by the Free Software Foundation.
 
 from canto_next.client import CantoClient
-from canto_next.encoding import decoder
 from canto_next.plugins import try_plugins
 
-from gui import CantoCursesGui
+from .gui import CantoCursesGui
 
 from threading import Thread
-from Queue import Queue
+from queue import Queue
 
 import logging
 
@@ -76,7 +75,7 @@ class CantoCurses(CantoClient):
             else:
                 CantoClient.__init__(self, None,\
                         port = self.port, address = self.addr)
-        except Exception, e:
+        except Exception as e:
             log.error("Error: %s" % e)
             sys.exit(-1)
 
@@ -117,7 +116,7 @@ class CantoCurses(CantoClient):
                 if r:
                     self.responses.put(r)
 
-        except Exception, e:
+        except Exception as e:
             log.error("Response thread exception: %s" % (e,))
 
         log.debug("Response thread exiting.")
@@ -158,7 +157,7 @@ class CantoCurses(CantoClient):
                 if pid == 0:
                     break
                 log.debug("CHLD %d has died: %d" % (pid, status))
-        except Exception, e:
+        except Exception as e:
             if e.errno == errno.ECHILD:
                 log.debug("CHLD no children?")
             else:
@@ -171,7 +170,7 @@ class CantoCurses(CantoClient):
     def reconnect(self):
         try:
             self.connect()
-        except Exception, e:
+        except Exception as e:
             log.error("Error reconnecting: %s" % e)
             self.gui.disconnected()
         else:
@@ -218,7 +217,7 @@ class CantoCurses(CantoClient):
         else:
             try:
                 os.makedirs(self.conf_dir)
-            except Exception, e:
+            except Exception as e:
                 log.error("Exception making %s : %s" % (self.conf_dir, e))
                 return -1
         return self.ensure_files()
@@ -254,7 +253,7 @@ class CantoCurses(CantoClient):
         except KeyboardInterrupt:
             pass
 
-        except Exception, e:
+        except Exception as e:
             tb = traceback.format_exc(e)
             log.error("Exiting on exception:")
             log.error("\n" + "".join(tb))
index d499480..68246bc 100644 (file)
@@ -19,9 +19,7 @@
 # impossible to cause the code to infinitely recurse with a value like
 # { 'a' : '%a' }.
 
-from canto_next.encoding import decoder
-
-from html import html_entity_convert, char_ref_convert
+from .html import html_entity_convert, char_ref_convert
 
 import traceback
 import logging
@@ -148,7 +146,7 @@ def _eval_simple(uni, values):
             escaped = True
 
         elif c == '}' and in_code and long_code:
-            r += unicode(eval(code, {}, values))
+            r += str(eval(code, {}, values))
             code = ""
             in_code = False
             long_code = False
@@ -158,7 +156,7 @@ def _eval_simple(uni, values):
             if long_code:
                 code += c
             elif c in values:
-                r += unicode(values[c])
+                r += str(values[c])
                 in_code = False
             else:
                 Exception("Unknown escape: %s" % c)
@@ -190,8 +188,6 @@ def eval_theme_string(parsed, values):
     return r
 
 def prep_for_display(s):
-    if type(s) == str:
-        s = decoder(s)
     s = s.replace("\\", "\\\\")
     s = s.replace("%", "\\%")
     s = html_entity_convert(s)
index 11d8dc8..615a562 100644 (file)
@@ -9,10 +9,10 @@
 from canto_next.plugins import Plugin
 from canto_next.hooks import on_hook, remove_hook
 
-from parser import prep_for_display
-from command import command_format
-from html import htmlparser
-from text import TextBox
+from .parser import prep_for_display
+from .command import command_format
+from .html import htmlparser
+from .text import TextBox
 
 import logging
 import re
@@ -32,7 +32,7 @@ class Reader(TextBox):
     def init(self, pad, callbacks):
         TextBox.init(self, pad, callbacks)
 
-        self.quote_rgx = re.compile(u"[\\\"](.*?)[\\\"]")
+        self.quote_rgx = re.compile("[\\\"](.*?)[\\\"]")
         on_hook("opt_change", self.on_opt_change)
 
     def die(self):
@@ -48,7 +48,7 @@ class Reader(TextBox):
 
     def on_attributes(self, attributes):
         sel = self.callbacks["get_var"]("reader_item")
-        if sel in attributes:
+        if sel.id in attributes:
             remove_hook("attributes", self.on_attributes)
 
             # Don't bother checking attributes. If we're still
@@ -119,7 +119,7 @@ class Reader(TextBox):
                 self.links += links
 
                 if reader_conf['show_description']:
-                    s += self.quote_rgx.sub(u"%6\"\\1\"%0", content)
+                    s += self.quote_rgx.sub("%6\"\\1\"%0", content)
 
                 if reader_conf['enumerate_links']:
                     s += "\n\n"
@@ -128,7 +128,7 @@ class Reader(TextBox):
                         text = prep_for_display(text)
                         url = prep_for_display(url)
 
-                        link_text = "[%B" + unicode(idx) + "%b][" +\
+                        link_text = "[%B" + str(idx) + "%b][" +\
                                 text + "]: " + url + "\n\n"
 
                         if t == "link":
index 3e310d3..424d7f5 100644 (file)
@@ -10,10 +10,10 @@ from canto_next.plugins import Plugin
 from canto_next.encoding import locale_enc
 from canto_next.hooks import on_hook, remove_hook
 
-from command import CommandHandler, command_format
-from taglist import TagList
-from input import InputBox
-import widecurse
+from .command import CommandHandler, command_format
+from .taglist import TagList
+from .input import InputBox
+from .widecurse import wsize
 
 from threading import Thread, Event, Lock
 import logging
@@ -97,15 +97,17 @@ class Screen(CommandHandler):
             curses.noecho()
             curses.start_color()
             curses.use_default_colors()
-        except Exception, e:
+        except Exception as e:
             log.error("Curses setup failed: %s" % e.msg)
             return -1
 
         self.height, self.width = self.stdscr.getmaxyx()
+        self.height = int(self.height)
+        self.width = int(self.width)
 
         color_conf = self.callbacks["get_opt"]("color")
 
-        for i in xrange(curses.COLOR_PAIRS):
+        for i in range(curses.COLOR_PAIRS):
             if ("%s" % i) not in color_conf:
                 continue
 
@@ -137,7 +139,7 @@ class Screen(CommandHandler):
         if "color" in conf:
             self.callbacks["set_var"]("needs_resize", True)
 
-        for key in conf.keys():
+        for key in list(conf.keys()):
             if type(conf[key]) == dict and "window" in conf[key]:
                 self.callbacks["set_var"]("needs_resize", True)
                 break
@@ -244,6 +246,8 @@ class Screen(CommandHandler):
         # Height + 1 to account for the last curses pad line
         # not being fully writable.
 
+        log.debug("h: %s w: %s" % (self.height, self.width))
+        log.debug("h: %s w: %s" % (height, width))
         pad = curses.newpad(height + 1, width)
 
         # Pass on callbacks we were given from CantoCursesGui
@@ -293,9 +297,9 @@ class Screen(CommandHandler):
             # possible slice we can *guarantee*.
 
             if orientation == "horizontal":
-                size = self._subw_size_width(unit, (width - used) / units)
+                size = self._subw_size_width(unit, int((width - used) / units))
             else:
-                size = self._subw_size_height(unit, (height - used) / units)
+                size = self._subw_size_height(unit, int((height - used) / units))
 
             used += size
 
@@ -320,12 +324,12 @@ class Screen(CommandHandler):
             # this set of windows.
 
             if orientation == "horizontal":
-                available = (width - used) / units
+                available = int((width - used) / units)
                 r = self._subw(unit, top, left + offset,\
                         height, available, "vertical")
                 sizes[i] = self._subw_layout_size(r, "width")
             else:
-                available = (height - used) / units
+                available = int((height - used) / units)
                 r = self._subw(unit, top + offset, left,\
                         available, width, "horizontal")
                 sizes[i] = self._subw_layout_size(r, "height")
@@ -605,7 +609,7 @@ class Screen(CommandHandler):
 
             # Overwrite struct output.
             f.seek(startpos, 0)
-            f.write("\0" * widecurse.wsize())
+            f.write("\0" * wsize())
             f.seek(endpos, 0)
 
         f.close()
@@ -627,7 +631,7 @@ class Screen(CommandHandler):
         try:
             c = int(c)
             if 0 < c <= curses.COLOR_PAIRS:
-                return (True, unicode(c - 1), r)
+                return (True, str(c - 1), r)
             else:
                 self.pair_error()
         except:
index 7b4e31b..cb28676 100644 (file)
@@ -9,8 +9,8 @@
 from canto_next.plugins import Plugin, PluginHandler
 from canto_next.hooks import on_hook, remove_hook
 
-from theme import FakePad, WrapPad, theme_print, theme_len, theme_process
-from parser import parse_conditionals, eval_theme_string, prep_for_display
+from .theme import FakePad, WrapPad, theme_print, theme_len, theme_process
+from .parser import parse_conditionals, eval_theme_string, prep_for_display
 
 import traceback
 import logging
@@ -70,7 +70,7 @@ class Story(PluginHandler):
         return self.id == other.id
 
     def on_attributes(self, attributes):
-        if self in attributes:
+        if self.id in attributes:
             # Don't bother checking attributes. If we're still
             # lacking, need_redraw will re-enable this hook
 
@@ -236,7 +236,7 @@ class Story(PluginHandler):
 
         try:
             parsed = parse_conditionals(state["fstring"])
-        except Exception, e:
+        except Exception as e:
             log.warn("Failed to parse conditionals in fstring: %s" % state["fstring"])
             log.warn("\n" + "".join(traceback.format_exc(e)))
             log.warn("Falling back to default.")
@@ -264,15 +264,15 @@ class Story(PluginHandler):
 
         # Prep all text values for display.
 
-        for value in values.keys():
-            if type(values[value]) in [unicode, str]:
+        for value in list(values.keys()):
+            if type(values[value]) in [str, str]:
                 values[value] = prep_for_display(values[value])
 
         values.update(passthru)
 
         try:
             s = eval_theme_string(parsed, values)
-        except Exception, e:
+        except Exception as e:
             log.warn("Failed to evaluate fstring: %s" % state["fstring"])
             log.warn("\n" + "".join(traceback.format_exc(e)))
             log.warn("Falling back to default")
@@ -285,9 +285,9 @@ class Story(PluginHandler):
 
         lines = 0
 
-        left = u"%C %c"
-        left_more = u"%C     %c"
-        right = u"%C %c"
+        left = "%C %c"
+        left_more = "%C     %c"
+        right = "%C %c"
 
         try:
             while s:
@@ -308,7 +308,7 @@ class Story(PluginHandler):
                             pad.getyx()[1] - (theme_len(right) + 3))
 
                     # Write out the ellipsis.
-                    for i in xrange(3):
+                    for i in range(3):
                         pad.waddch('.')
 
                     # Handling any dangling codes
@@ -328,7 +328,7 @@ class Story(PluginHandler):
         # case scenario is that one story's worth of space
         # is going to be fucked up.
 
-        except Exception, e:
+        except Exception as e:
             log.debug("Story exception: %s" % (e,))
 
         # Return number of lines this story took to render entirely.
index a0659ba..77ff8fb 100644 (file)
@@ -8,9 +8,9 @@
 
 from canto_next.hooks import call_hook, on_hook, remove_hook
 
-from parser import parse_conditionals, eval_theme_string, prep_for_display
-from theme import FakePad, WrapPad, theme_print
-from story import Story
+from .parser import parse_conditionals, eval_theme_string, prep_for_display
+from .theme import FakePad, WrapPad, theme_print
+from .story import Story
 
 import traceback
 import logging
@@ -95,7 +95,7 @@ class Tag(list):
             self.need_redraw()
 
     def on_tag_opt_change(self, opts):
-        if self.tag in opts.keys():
+        if self.tag in list(opts.keys()):
             tc = opts[self.tag]
             if "collapsed" in tc:
                 self.need_refresh()
@@ -303,7 +303,7 @@ class Tag(list):
 
         try:
             parsed = parse_conditionals(fstring)
-        except Exception, e:
+        except Exception as e:
             log.warn("Failed to parse conditionals in fstring: %s" %
                     fstring)
             log.warn("\n" + "".join(traceback.format_exc(e)))
@@ -323,15 +323,15 @@ class Tag(list):
 
         # Prep all text values for display.
 
-        for value in values.keys():
-            if type(values[value]) in [unicode, str]:
+        for value in list(values.keys()):
+            if type(values[value]) in [str, str]:
                 values[value] = prep_for_display(values[value])
 
         values.update(passthru)
 
         try:
             s = eval_theme_string(parsed, values)
-        except Exception, e:
+        except Exception as e:
             log.warn("Failed to evaluate fstring: %s" % fstring)
             log.warn("\n" + "".join(traceback.format_exc(e)))
             log.warn("Falling back to default")
@@ -339,12 +339,12 @@ class Tag(list):
             parsed = parse_conditionals(DEFAULT_TAG_FSTRING)
             s = eval_theme_string(parsed, values)
 
-        s += u"\n"
+        s += "\n"
 
         lines = 0
 
         while s:
-            s = theme_print(pad, s, width, u"", u"")
+            s = theme_print(pad, s, width, "", "")
             lines += 1
 
         return lines
index 532b23e..e587ca2 100644 (file)
@@ -10,9 +10,9 @@ from canto_next.hooks import on_hook, remove_hook, call_hook
 from canto_next.plugins import Plugin
 from canto_next.encoding import encoder
 
-from command import command_format
-from guibase import GuiBase
-from reader import Reader
+from .command import command_format
+from .guibase import GuiBase
+from .reader import Reader
 
 import logging
 import curses
@@ -664,7 +664,7 @@ class TagList(GuiBase):
     def search(self, regex):
         try:
             rgx = re.compile(regex)
-        except Exception, e:
+        except Exception as e:
             self.callbacks["set_var"]("error_msg", e)
             return
 
@@ -882,7 +882,7 @@ class TagList(GuiBase):
             else:
                 try:
                     tag = self.tag_by_item(target_obj)
-                except Exception, e:
+                except Exception as e:
                     if target_obj not in vistags:
                         # Not a story in tags and not a tag? Reset.
                         self.callbacks["set_var"]("target_obj", vistags[0])
index 3139183..b07ca28 100644 (file)
@@ -6,10 +6,10 @@
 #   it under the terms of the GNU General Public License version 2 as 
 #   published by the Free Software Foundation.
 
-from theme import FakePad, WrapPad, theme_print, theme_lstrip, theme_border
-from command import command_format
-from guibase import GuiBase
-from theme import theme_print
+from .theme import FakePad, WrapPad, theme_print, theme_lstrip, theme_border
+from .command import command_format
+from .guibase import GuiBase
+from .theme import theme_print
 
 import logging
 import curses
@@ -91,11 +91,11 @@ class TextBox(GuiBase):
     def render_top_border(self, pad):
         tb, lb, bb, rb = self.callbacks["border"]()
 
-        lc = u" "
+        lc = " "
         if lb:
             lc = "%1%C" + theme_border("tl") + "%c%0"
 
-        rc = u" "
+        rc = " "
         if rb:
             rc = "%1%C" + theme_border("tr") + "%c%0"
 
@@ -105,11 +105,11 @@ class TextBox(GuiBase):
     def render_bottom_border(self, pad):
         tb, lb, bb, rb = self.callbacks["border"]()
 
-        lc = u" "
+        lc = " "
         if lb:
             lc = "%1%C" + theme_border("bl") + "%c%0"
 
-        rc = u" "
+        rc = " "
         if rb:
             rc = "%1%C" + theme_border("br") + "%c%0"
 
@@ -130,10 +130,10 @@ class TextBox(GuiBase):
 
         # Prepare left and right borders
 
-        l = u" "
+        l = " "
         if lb:
             l = "%1%C" + theme_border("ls") + " %c%0"
-        r = u" "
+        r = " "
         if rb:
             r = "%1%C " + theme_border("rs") + "%c%0"
 
index 2334a87..c8ada0e 100644 (file)
@@ -7,7 +7,7 @@
 #   published by the Free Software Foundation.
 
 from canto_next.encoding import encoder, locale_enc
-from widecurse import waddch, wcwidth
+from .widecurse import waddch, wcwidth
 
 import curses
 
@@ -261,7 +261,7 @@ def theme_process(pad, uni):
 
 def theme_lstrip(pad, uni):
     newlines = 0
-    codes = u""
+    codes = ""
     escaped = False
 
     for i, c in enumerate(uni):
@@ -292,14 +292,14 @@ def theme_lstrip(pad, uni):
 
     return (newlines * "\n") + r
 
-utf_chars = { "ls" : u"│",
-              "rs" : u"│",
-              "ts" : u"─",
-              "bs" : u"─",
-              "tl" : u"┌",
-              "tr" : u"┐",
-              "bl" : u"└",
-              "br" : u"┘" }
+utf_chars = { "ls" : "│",
+              "rs" : "│",
+              "ts" : "─",
+              "bs" : "─",
+              "tl" : "┌",
+              "tr" : "┐",
+              "bl" : "└",
+              "br" : "┘" }
 
 ascii_chars = { "ls" : "|",
                 "rs" : "|",
index 8ecfda8..69329c9 100644 (file)
@@ -82,15 +82,27 @@ static PyObject * py_wsize(PyObject *self, PyObject *args)
     return Py_BuildValue("i", sizeof(WINDOW));
 }
 
-static PyMethodDef MvWMethods[] = {
-    {"waddch", py_waddch, METH_VARARGS, "waddch() wrapper."},
-    {"wcwidth", py_wcwidth, METH_VARARGS, "wcwidth() wrapper."},
-    {"wsize", py_wsize, METH_VARARGS, "Returns sizeof(WINDOW)"},
-    {NULL, NULL, 0, NULL}
+static PyMethodDef WCMethods[] = {
+    {"waddch", (PyCFunction)py_waddch, METH_VARARGS, "waddch() wrapper."},
+    {"wcwidth", (PyCFunction)py_wcwidth, METH_VARARGS, "wcwidth() wrapper."},
+    {"wsize", (PyCFunction)py_wsize, METH_VARARGS, "Returns sizeof(WINDOW)"},
+    {NULL, NULL},
+};
+
+static struct PyModuleDef moduledef = {
+       PyModuleDef_HEAD_INIT,
+       "widecurse",
+       NULL,
+       -1,
+       WCMethods,
+       NULL,
+       NULL,
+       NULL,
+       NULL
 };
 
 PyMODINIT_FUNC
-initwidecurse(void)
+PyInit_widecurse(void)
 {
-    Py_InitModule("widecurse", MvWMethods);
+    return PyModule_Create(&moduledef);
 }
diff --git a/tests/README b/tests/README
deleted file mode 100644 (file)
index 000ea31..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-Canto-curses Test Suite
-
-REQUIRED:
-
-*In addition to the usual c-c requirements*
-
-xterm
-bash
-gzip
-hexdump
-diff
-canto-remote
-canto-daemon
-
-UTF-8 encoding (set LC_ALL if you don't use one by default)
-
-NOTES:
-
-These are blackbox tests, which means you start the programs, you give a set
-input and then you test that the output looks as expected. These are also
-rife with off-the-cuff timings which seem generous (considering they're
-usually spacing out keystrokes), but could cause the tests to fail on slower
-hardware. This also means that these tests take a bit to run.
-
-TILING WMS:
-
-This test suite also relies on being able to set the geometry of the xterm.
-This is overridden by tiling wms, so in order for the tests to pass, you have
-to float the relevant xterms. They are all given the title `canto-test` (no
-quotes) for this purpose.
-
-RUN EXAMPLE:
-
-./run.sh */
diff --git a/tests/addfeed/skel/canto-addfeed.xml b/tests/addfeed/skel/canto-addfeed.xml
deleted file mode 100644 (file)
index 4a1d37b..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<rss version="2.0">
-    <channel>
-        <title>TEST FEED OMFG</title>
-        <item>
-            <title> B. This is a test feed. </title>
-            <description> Blah blah blah </description>
-        </item>
-        <item>
-            <title> C. This is a test feed. </title>
-            <description> Blah blah blah </description>
-        </item>
-        <item>
-            <title> E. This is a test feed. </title>
-            <description> Blah blah blah </description>
-        </item>
-        <item>
-            <title> D. This is a test feed. </title>
-            <description> Blah blah blah </description>
-        </item>
-        <item>
-            <title> A. This is a test feed. </title>
-            <description> Blah blah blah </description>
-        </item>
-    </channel>
-</rss>
diff --git a/tests/addfeed/skel/conf b/tests/addfeed/skel/conf
deleted file mode 100644 (file)
index d3ca833..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-[Feed Static]
-url = file:///tmp/canto.xml
-order = 0
-
-[Feed Static 2]
-url = file:///tmp/canto2.xml
-order = 1
diff --git a/tests/addfeed/skel/expected.gz b/tests/addfeed/skel/expected.gz
deleted file mode 100644 (file)
index 6047c0f..0000000
Binary files a/tests/addfeed/skel/expected.gz and /dev/null differ
diff --git a/tests/addfeed/skel/feeds b/tests/addfeed/skel/feeds
deleted file mode 100644 (file)
index 4fcf855..0000000
Binary files a/tests/addfeed/skel/feeds and /dev/null differ
diff --git a/tests/addfeed/skel/script.sh b/tests/addfeed/skel/script.sh
deleted file mode 100755 (executable)
index a47ea1f..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/bash
-
-# This tests the remote: capability as well as the ability to show
-# freshly added feeds immediately.
-
-canto-daemon -v -D ./ &
-
-cp canto-addfeed.xml /tmp/
-
-function stimulate() {
-    sleep 3
-
-    echo -n ":"
-    sleep 0.5
-    echo "remote addfeed file:///tmp/canto-addfeed.xml"
-    sleep 0.5
-    echo -n " "
-
-    sleep 0.5
-    echo -n "\\"
-    sleep 3;
-
-    echo -n ":"
-    sleep 0.5
-    echo "dump-screen canto-screen"
-
-    echo -n "q"
-}
-
-stimulate | canto-curses -v -D ./
-
-canto-remote -D ./ kill
-
-rm /tmp/canto*.xml
diff --git a/tests/baseline/skel/conf b/tests/baseline/skel/conf
deleted file mode 100644 (file)
index d3ca833..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-[Feed Static]
-url = file:///tmp/canto.xml
-order = 0
-
-[Feed Static 2]
-url = file:///tmp/canto2.xml
-order = 1
diff --git a/tests/baseline/skel/expected.gz b/tests/baseline/skel/expected.gz
deleted file mode 100644 (file)
index 5bcef2a..0000000
Binary files a/tests/baseline/skel/expected.gz and /dev/null differ
diff --git a/tests/baseline/skel/feeds b/tests/baseline/skel/feeds
deleted file mode 100644 (file)
index 4fcf855..0000000
Binary files a/tests/baseline/skel/feeds and /dev/null differ
diff --git a/tests/baseline/skel/script.sh b/tests/baseline/skel/script.sh
deleted file mode 100755 (executable)
index 0b171eb..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-
-# This test merely dumps the initial interface under
-# a known set of conditions. This will only catch the
-# most basic errors.
-
-canto-daemon -v -D ./ &
-
-function stimulate() {
-    sleep 3;
-
-    echo -n ":"
-    sleep 0.5
-    echo "dump-screen canto-screen"
-
-    echo -n "q"
-}
-
-stimulate | canto-curses -v -D ./
-
-canto-remote -D ./ kill
diff --git a/tests/delfeed/skel/conf b/tests/delfeed/skel/conf
deleted file mode 100644 (file)
index d3ca833..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-[Feed Static]
-url = file:///tmp/canto.xml
-order = 0
-
-[Feed Static 2]
-url = file:///tmp/canto2.xml
-order = 1
diff --git a/tests/delfeed/skel/expected.gz b/tests/delfeed/skel/expected.gz
deleted file mode 100644 (file)
index 279ae96..0000000
Binary files a/tests/delfeed/skel/expected.gz and /dev/null differ
diff --git a/tests/delfeed/skel/feeds b/tests/delfeed/skel/feeds
deleted file mode 100644 (file)
index 4fcf855..0000000
Binary files a/tests/delfeed/skel/feeds and /dev/null differ
diff --git a/tests/delfeed/skel/script.sh b/tests/delfeed/skel/script.sh
deleted file mode 100755 (executable)
index 402541e..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/bash
-
-# This tests the remote: capability as well as the immediate
-# removal of deleted tags. In addition, it removes the first
-# on screen tag, so it tests the removal of first_item and
-# tag_obj.
-
-canto-daemon -v -D ./ &
-
-function stimulate() {
-    sleep 3
-
-    echo -n ":"
-    sleep 0.5
-    echo "remote delfeed file:///tmp/canto.xml"
-    sleep 0.5
-    echo -n " "
-
-    sleep 2
-    echo -n ":"
-    sleep 0.5
-    echo "dump-screen canto-screen"
-
-    echo -n "q"
-}
-
-stimulate | canto-curses -v -D ./
-
-canto-remote -D ./ kill
diff --git a/tests/enum_height/skel/conf b/tests/enum_height/skel/conf
deleted file mode 100644 (file)
index 44328f5..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-[DEFAULT]
-home = /home/jack
-cwd = /home/jack/src/canto-curses/tests/addfeed
-
-[Feed Static]
-url = file:///tmp/canto.xml
-order = 0
-
-[Feed Static 2]
-url = file:///tmp/canto2.xml
-order = 1
-
-[Feed TEST FEED OMFG]
-url = file:///tmp/canto-addfeed.xml
-order = 2
-
diff --git a/tests/enum_height/skel/expected.gz b/tests/enum_height/skel/expected.gz
deleted file mode 100644 (file)
index c2e8289..0000000
Binary files a/tests/enum_height/skel/expected.gz and /dev/null differ
diff --git a/tests/enum_height/skel/feeds b/tests/enum_height/skel/feeds
deleted file mode 100644 (file)
index 6c9f08f..0000000
Binary files a/tests/enum_height/skel/feeds and /dev/null differ
diff --git a/tests/enum_height/skel/script.sh b/tests/enum_height/skel/script.sh
deleted file mode 100755 (executable)
index c89ab50..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/bash
-
-# This tests pinching the enumerated objects, to make sure
-# that they don't expand vertically and prints the ellipsis
-
-canto-daemon -v -D ./ &
-
-cp canto-addfeed.xml /tmp/
-
-function stimulate() {
-    sleep 3
-
-    echo -n "e"
-
-    sleep 3
-    echo -n ":"
-    sleep 0.5
-    echo "dump-screen canto-screen"
-
-    echo -n "q"
-}
-
-stimulate | canto-curses -v -D ./
-
-canto-remote -D ./ kill
-
-rm /tmp/canto*.xml
diff --git a/tests/run.sh b/tests/run.sh
deleted file mode 100755 (executable)
index 23fc4a1..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash
-
-for test_dir in "$@"; do
-    # Eliminate old cruft
-    rm -f $test_dir/* 2>/dev/null
-
-    # Copy in skel
-    cp $test_dir/skel/* $test_dir/
-
-    # Run test script with given size.
-
-    cd $test_dir
-    xterm -title "canto-test" -geometry 80x50 -e ./script.sh
-    cd ..
-
-    # Compare outputs
-    hexdump $test_dir/canto-screen > $test_dir/output
-
-    gunzip -c $test_dir/expected.gz | hexdump > $test_dir/expected
-
-    TESTDIFF=`diff -u ./$test_dir/output ./$test_dir/expected`
-    if [ -n "$TESTDIFF" ]; then
-        echo "TEST $test_dir FAILED"
-        diff -u ./$test_dir/output ./$test_dir/expected
-    else
-        echo "TEST $test_dir OK"
-    fi
-done