General cleanup. Stopped using older 'except Error, var' syntax.

This commit is contained in:
karxi 2016-11-29 15:20:41 -05:00
parent e40aac88ac
commit 3a48cf204b
13 changed files with 168 additions and 143 deletions

View file

@ -39,6 +39,32 @@ Features
* Overhaul debugging
* Make a console to display debug info without requiring us to run from console
* Debug generic.py's CaseInsensitiveDict/replace it with mine
* Overhaul messaging so Chan/Nick/Memo Servs all use the same code (and lexer)
* Implement MemoServ support
* Add support for displaying more verbose information (e.g. Cease messages which tell you more than the abbreviation of who left)
* Make Pesterchum recognize conventional /mes so they aren't invisible
* Fix NickServ auto-login things
* Fix memo autojoin
* Tell user when NickServ handles are going to expire
* Tell user when old handles have D/C'd? Offer autoghost support?!
* Add more comprehensive status support - IDLE, DND, INVISIBLE for now - or at least add similar functionality.
* SEPARATE FUNCTIONALITY from CONNECTED STATE!! This is a huge problem! Being shunted off our nick closes windows and breaks things! Just D/C and reconnect?
* It'd probably be best to give an option to either CHANGE NICKS or DISCONNECT upon nick collision...? But, then how would we GHOST?
* Maybe GHOSTing should use auto-identify to ensure- no, that doesn't work, because we can't ident into a specified nick without being ON it. Need GD's help to fix....
* Separate Pesterchum system handling from window handling. Dicts should be stored and maintained via dicts - even a refined version of what I used for textsub.
* Doing it this way means I can fix the case in/sensitivity issue, too.
* Finish creating the sound wrapper. Just make it check what the type of sound needed is upon creation, and instantiate a private class based off of that.
* There is basically no good way to do this without moving to Qt5. I might try that myself later, but that's a long-term goal.
* Toggle individual tab flash / alert sounds (from the same right-click memo that lets us toggle OOC)
* Make it possible to test quirk things and such without connecting? This'd be hard to separate out, but useful.
Debugging
----
* Make small, simplistic windows that allow the viewing of internal variables pertaining to things like set quirks, users present, etc.
* Make a window that can be used to interface with the script directly - a simple Python console.
Bugs
----
@ -58,6 +84,8 @@ Bugs
* +c is not properly recognized on join, nor does it stop someone from reenabling their quirk (let ops and above ignore it)
* Chumlist handles groups pretty badly (no using the same name as a handle, for example? Needs an errormessage at least)
* PESTERCHUM: messages are sent to things like NickServ
* Log folder/file names are not case-sensitive, so they break on non-Windows systems
* Capitalized /me's don't render (should forcibly lowercase them)
Windows Bugs
------------

View file

@ -462,7 +462,7 @@ class PesterText(QtGui.QTextEdit):
else:
self.sending.sendinglabel.setText("F41L3D: %s %s" % (response.status, response.reason))
hconn.close()
except Exception, e:
except Exception as e:
self.sending.sendinglabel.setText("F41L3D: %s" % (e))
del self.sending

View file

@ -224,7 +224,7 @@ try:
print "Invalid input, try again"
except KeyboardInterrupt:
print ""
except Exception, e:
except Exception as e:
error = -1
finally:
if error == -1:

View file

@ -2234,7 +2234,7 @@ def _parse_date(dateString):
raise ValueError
map(int, date9tuple)
return date9tuple
except Exception, e:
except Exception as e:
if _debug: sys.stderr.write('%s raised %s\n' % (handler.__name__, repr(e)))
pass
return None
@ -2458,7 +2458,7 @@ def parse(url_file_stream_or_string, etag=None, modified=None, agent=None, refer
try:
f = _open_resource(url_file_stream_or_string, etag, modified, agent, referrer, handlers)
data = f.read()
except Exception, e:
except Exception as e:
result['bozo'] = 1
result['bozo_exception'] = e
data = ''
@ -2469,7 +2469,7 @@ def parse(url_file_stream_or_string, etag=None, modified=None, agent=None, refer
if gzip and f.headers.get('content-encoding', '') == 'gzip':
try:
data = gzip.GzipFile(fileobj=_StringIO(data)).read()
except Exception, e:
except Exception as e:
# Some feeds claim to be gzipped but they're not, so
# we get garbage. Ideally, we should re-request the
# feed without the 'Accept-encoding: gzip' header,
@ -2480,7 +2480,7 @@ def parse(url_file_stream_or_string, etag=None, modified=None, agent=None, refer
elif zlib and f.headers.get('content-encoding', '') == 'deflate':
try:
data = zlib.decompress(data, -zlib.MAX_WBITS)
except Exception, e:
except Exception as e:
result['bozo'] = 1
result['bozo_exception'] = e
data = ''
@ -2609,7 +2609,7 @@ def parse(url_file_stream_or_string, etag=None, modified=None, agent=None, refer
saxparser._ns_stack.append({'http://www.w3.org/XML/1998/namespace':'xml'})
try:
saxparser.parse(source)
except Exception, e:
except Exception as e:
if _debug:
import traceback
traceback.print_stack()

View file

@ -204,7 +204,7 @@ class IRCClient:
logging.info('error: closing socket')
self.socket.close()
raise se
except Exception, e:
except Exception as e:
logging.debug("other exception: %s" % e)
raise e
else:
@ -270,7 +270,7 @@ class IRCApp:
try:
clientdesc.con.next()
except Exception, e:
except Exception as e:
logging.error('client error %s' % e)
logging.error(traceback.format_exc())
if clientdesc.autoreconnect:

View file

@ -104,7 +104,7 @@ class CommandHandler(object):
try:
f(*args)
except Exception, e:
except Exception as e:
logging.error('command raised %s' % e)
logging.error(traceback.format_exc())
raise CommandError(command)
@ -150,7 +150,7 @@ class DefaultBotCommandHandler(CommandHandler):
else:
try:
f = self.get(arg)
except CommandError, e:
except CommandError as e:
helpers.msg(self.client, dest, str(e))
return
@ -197,7 +197,7 @@ class BotCommandHandler(DefaultCommandHandler):
try:
self.command_handler.run(command, prefix, dest, *arg)
except CommandError, e:
except CommandError as e:
helpers.msg(self.client, dest, str(e))
return True

View file

@ -220,7 +220,8 @@ kxpclexer = lexercon.Pesterchum()
def kxlexMsg(string):
# Do a bit of sanitization.
msg = unicode(string)
# TODO: Let people paste line-by-line normally.
# TODO: Let people paste line-by-line normally. Maybe have a mass-paste
# right-click option?
msg = msg.replace('\n', ' ').replace('\r', ' ')
# Something the original doesn't seem to have accounted for.
# Replace tabs with 4 spaces.
@ -340,12 +341,22 @@ def kxsplitMsg(lexed, fmt="pchum", maxlen=None, debug=False):
Keep in mind that there's a little bit of magic involved in this at the
moment; some unsafe assumptions are made."""
# NOTE: Keep in mind that lexercon CTag objects convert to "r,g,b" format.
# This means that they're usually going to be fairly long.
# Support for changing this will probably be added later, but it won't work
# properly with Chumdroid...I'll probably have to leave it as an actual
# config option that's applied to the parser.
# Procedure: Lex. Convert for lengths as we go, keep starting tag
# length as we go too. Split whenever we hit the limit, add the tags to
# the start of the next line (or just keep a running line length
# total), and continue.
# N.B.: Keep the end tag length too. (+4 for each.)
# Copy the list so we can't break anything.
# TODO: There's presently an issue where certain combinations of color
# codes end up being added as a separate, empty line. This is a bug, of
# course, and should be looked into.
lexed = list(lexed)
working = []
output = []
@ -479,7 +490,7 @@ def kxsplitMsg(lexed, fmt="pchum", maxlen=None, debug=False):
if text_preproc:
# If we got here, it means we overflowed due to text - which
# means we also split and added it to working. There's no
# reason to continue and add it twice.
# reason to go on and add it twice.
# This could be handled with an elif chain, but eh.
continue
# If we got here, it means we haven't done anything with 'msg' yet,
@ -640,7 +651,7 @@ def kxhandleInput(ctx, text=None, flavor=None):
# files for the original sentMessage variants.
if flavor is None:
return ValueError("A flavor is needed to determine suitable logic!")
raise ValueError("A flavor is needed to determine suitable logic!")
if text is None:
# Fetch the raw text from the input box.

View file

@ -15,19 +15,21 @@ reqmissing = []
optmissing = []
try:
from PyQt4 import QtGui, QtCore
except ImportError, e:
except ImportError as e:
module = str(e)
if module.startswith("No module named ") or \
module.startswith("cannot import name "):
reqmissing.append(module[module.rfind(" ")+1:])
else: print e
del module
try:
import pygame
except ImportError, e:
except ImportError as e:
pygame = None
module = str(e)
if module[:16] == "No module named ": optmissing.append(module[16:])
else: print e
del module
if reqmissing:
print "ERROR: The following modules are required for Pesterchum to run and are missing on your system:"
for m in reqmissing: print "* "+m
@ -1022,10 +1024,10 @@ class PesterWindow(MovingWindow):
try:
themeChecker(self.theme)
except ThemeException, (inst):
except ThemeException as inst:
print "Caught: " + inst.parameter
themeWarning = QtGui.QMessageBox(self)
themeWarning.setText("Theme Error: %s" % (inst))
themeWarning.setText("Theme Error: %s" % inst)
themeWarning.exec_()
self.theme = pesterTheme("pesterchum")
@ -1679,15 +1681,15 @@ class PesterWindow(MovingWindow):
else:
sound.setVolume(vol)
except Exception as err:
print "Couldn't set volumme: {}".format(err)
print "Couldn't set volume: {}".format(err)
def changeTheme(self, theme):
# check theme
try:
themeChecker(theme)
except ThemeException, (inst):
except ThemeException as inst:
themeWarning = QtGui.QMessageBox(self)
themeWarning.setText("Theme Error: %s" % (inst))
themeWarning.setText("Theme Error: %s" % inst)
themeWarning.exec_()
theme = pesterTheme("pesterchum")
return
@ -2521,7 +2523,7 @@ class PesterWindow(MovingWindow):
newmodes = self.optionmenu.modechange.text()
if newmodes:
self.setChannelMode.emit(self.profile().handle, newmodes, "")
except Exception, e:
except Exception as e:
logging.error(e)
finally:
self.optionmenu = None
@ -2560,7 +2562,7 @@ class PesterWindow(MovingWindow):
if override or themename != self.theme.name:
try:
self.changeTheme(pesterTheme(themename))
except ValueError, e:
except ValueError as e:
themeWarning = QtGui.QMessageBox(self)
themeWarning.setText("Theme Error: %s" % (e))
themeWarning.exec_()

View file

@ -252,6 +252,12 @@ class Pesterchum(Lexer):
_ctag_end = re.compile(r"</c>", flags=re.I)
_mecmdre = re.compile(r"^(/me|PESTERCHUM:ME)(\S*)")
# TODO: At some point, this needs to have support for setting up
# optimization controls - so ctags will be rendered down into things like
# "<c=#FAF>" instead of "<c=#FFAAFF>".
# I'd make this the default, but I'd like to retain *some* compatibility
# with Chumdroid's faulty implementation...or at least have the option to.
def lex(self, string):
lexlist = [
##(mecmd, self._mecmdre),

View file

@ -37,27 +37,6 @@ class Color(object):
# TODO: color_for_name()
# TODO: Split __init__, partly using __new__, so the former just has to do
# conversions
##def __new__(cls, *args, **kwargs):
## nargs = len(args)
## if nargs > 0: arg = args[0]
## if (nargs == 1
## and isinstance(arg, basestr) and not arg.startswith('#')
## ):
## # Try to look up the color name
## name = arg.lower()
## try:
## color = _svg_colors[name]
## except LookupError:
## # We don't have a color with that name
## raise ValueError("No color with name '%s' found" % name)
## else:
## # Hand over a copy of the color we found
## return cls(color)
## else:
## return super(Color, cls).__new__(cls)
## inst = super(Color, cls).__new__(cls)
## inst.ccode = ''
## nargs = len(args)
def __init__(self, *args, **kwargs):
self.ccode = ''
self.closest_name = self.name = None
@ -284,37 +263,47 @@ class Color(object):
def hexstr_to_rgb(cls, hexstr):
hexstr = cls.sanitize_hex(hexstr)
hexstr = hexstr.lstrip('#')
# This is ugly, but the purpose is simple and it's accomplished in a
# single line...it just runs through the string, picking two characters
# at a time and converting them from hex values to ints.
result = tuple(int(hexstr[i:i+2], 16) for i in range(len(hexstr))[::2])
if len(hexstr) == 3:
# NOTE: This will presently never happen, due to the way
# sanitize_hex works.
# We have something like '#FEF', which means '#FFEEFF'. Expand it
# first.
# Multiplying each element by 17 expands it. Dividing it does the
# opposite.
result = tuple( (int(h, 16) * 17) for h in hexstr )
else:
# This is ugly, but the purpose is simple and it's accomplished in
# a single line...it just runs through the string, picking two
# characters at a time and converting them from hex values to ints.
result = tuple(
int(hexstr[i:i+2], 16) for i in range(0, len(hexstr), 2)
)
return result
##working = collections.deque(hexstr)
##result = []
### The alternative to doing it this way would be to use an int-driven
### 'for' loop, or similar which might be preferable
##while working:
## # Fetch the next two args and convert them to an int
## i = int(working.popleft() + working.popleft(), 16)
## result.append(i)
@staticmethod
def rgb_to_hexstr(red, green, blue):
def rgb_to_hexstr(red, green, blue, compress=False):
rgb = [red, green, blue]
rgb = map(abs, rgb)
# Preemptively add the '#' to our result
result = ['#']
result = []
for c in rgb:
### Convert to hex, stripping the leading "0x" that Python adds
##c = hex(c).lstrip("0x", 1)
### Add a '0' in front if it's just a single digit
##c = ('0' + c)[-2:]
c = "%02X" % c
# Append to our result
result.append(c)
if compress:
# Try to compress this down from six characters to three.
# Basically the same thing as reduce_hexstr. Might make it use that
# later.
for h in result:
if h[0] != h[1]:
# We can't compress this; alas.
# Break out so we don't go to the 'else' segment.
break
else:
# All of our codes were doubles; compress them all down.
result = [h[0] for h in result]
# Join and return the result
return ''.join(result)
return '#' + ''.join(result)
# These next two are from http://www.easyrgb.com/index.php?X=MATH
@staticmethod
@ -355,37 +344,46 @@ class Color(object):
@staticmethod
def reduce_hexstr(hexstr):
"""Attempt to reduce a six-character hexadecimal color code down to a
four-character one."""
orig = hexstr
hexstr = hexstr.lstrip('#')
lhexstr = hexstr.lower()
strlen = len(hexstr)
working = ['#']
for i in range(strlen)[::2]:
if lhexstr[i] == lhexstr[i+1]:
# The two characters fetched are the same, so we can reduce
working.append(hexstr[i])
else:
# The two characters differ, so we can't actually reduce this
# string at all; just return the original
h = hexstr.upper()
for i in range(0, strlen, 2):
if h[i] != h[i+1]:
# We found a match that wouldn't work; give back the old value.
return orig
# If we got here, we successfully reduced
return ''.join(working)
else:
# All of these can be reduced; do so and return.
return '#' + hexstr[::2]
@staticmethod
def sanitize_hex(hexstr):
orig = hexstr
hexstr = hexstr.upper()
# We don't need the leading hash mark for now
hexstr = hexstr.lstrip('#')
strlen = len(hexstr)
if strlen == 6:
return '#' + hexstr
# We just need to test this for validity. Fall through to the end.
pass
elif strlen == 3:
# We have a short (CSS style) code; duplicate all of the characters
hexstr = [c + c for c in hexstr]
hexstr = ''.join(hexstr)
return '#' + hexstr
# Should probably error out, but that can wait until later
else:
raise ValueError(
"Invalid hexadecimal value provided: %s" % orig
)
try:
# Make sure it works/is readable (no invalid characters).
int(hexstr, 16)
except ValueError:
raise ValueError(
"Invalid hexadecimal value provided: %s" % orig
)
return '#' + hexstr
def to_cielab_tuple(self):

View file

@ -97,9 +97,8 @@ class userConfig(object):
self.NEWCONVO = 8
self.INITIALS = 16
self.filename = _datadir+"pesterchum.js"
fp = open(self.filename)
with open(self.filename) as fp:
self.config = json.load(fp)
fp.close()
if self.config.has_key("defaultprofile"):
self.userprofile = userProfile(self.config["defaultprofile"])
else:
@ -110,28 +109,21 @@ class userConfig(object):
if not os.path.exists(self.logpath):
os.makedirs(self.logpath)
try:
fp = open("%s/groups.js" % (self.logpath), 'r')
with open("%s/groups.js" % (self.logpath), 'r') as fp:
self.groups = json.load(fp)
fp.close()
except IOError:
except (IOError, ValueError):
self.groups = {}
fp = open("%s/groups.js" % (self.logpath), 'w')
with open("%s/groups.js" % (self.logpath), 'w') as fp:
json.dump(self.groups, fp)
fp.close()
except ValueError:
self.groups = {}
fp = open("%s/groups.js" % (self.logpath), 'w')
json.dump(self.groups, fp)
fp.close()
def chums(self):
if not self.config.has_key('chums'):
self.set("chums", [])
return self.config.get('chums', [])
def setChums(self, newchums):
fp = open(self.filename) # what if we have two clients open??
with open(self.filename) as fp:
# what if we have two clients open??
newconfig = json.load(fp)
fp.close()
oldchums = newconfig['chums']
# Time to merge these two! :OOO
for c in list(set(oldchums) - set(newchums)):
@ -225,9 +217,9 @@ class userConfig(object):
return self.config.get('ghostchum', False)
def addChum(self, chum):
if chum.handle not in self.chums():
fp = open(self.filename) # what if we have two clients open??
with open(self.filename) as fp:
# what if we have two clients open??
newconfig = json.load(fp)
fp.close()
newchums = newconfig['chums'] + [chum.handle]
self.set("chums", newchums)
def removeChum(self, chum):
@ -285,11 +277,10 @@ class userConfig(object):
self.groups['groups'] = groups
try:
jsonoutput = json.dumps(self.groups)
except ValueError, e:
except ValueError as e:
raise e
fp = open("%s/groups.js" % (self.logpath), 'w')
with open("%s/groups.js" % (self.logpath), 'w') as fp:
fp.write(jsonoutput)
fp.close()
def server(self):
if hasattr(self.parent, 'serverOverride'):
@ -319,11 +310,10 @@ class userConfig(object):
self.config[item] = setting
try:
jsonoutput = json.dumps(self.config)
except ValueError, e:
except ValueError as e:
raise e
fp = open(self.filename, 'w')
with open(self.filename, 'w') as fp:
fp.write(jsonoutput)
fp.close()
def availableThemes(self):
themes = []
# Load user themes.
@ -372,12 +362,11 @@ class userProfile(object):
self.mentions = []
self.autojoins = []
else:
fp = open("%s/%s.js" % (self.profiledir, user))
with open("%s/%s.js" % (self.profiledir, user)) as fp:
self.userprofile = json.load(fp)
fp.close()
try:
self.theme = pesterTheme(self.userprofile["theme"])
except ValueError, e:
except ValueError:
self.theme = pesterTheme("pesterchum")
self.lastmood = self.userprofile.get('lastmood', self.theme["main/defaultmood"])
self.chat = PesterProfile(self.userprofile["handle"],
@ -402,7 +391,7 @@ class userProfile(object):
try:
with open(_datadir+"passwd.js") as fp:
self.passwd = json.load(fp)
except Exception, e:
except:
self.passwd = {}
self.autoidentify = False
self.nickservpass = ""
@ -479,11 +468,10 @@ class userProfile(object):
return
try:
jsonoutput = json.dumps(self.userprofile)
except ValueError, e:
except ValueError as e:
raise e
fp = open("%s/%s.js" % (self.profiledir, handle), 'w')
with open("%s/%s.js" % (self.profiledir, handle), 'w') as fp:
fp.write(jsonoutput)
fp.close()
def saveNickServPass(self):
# remove profiles with no passwords
for h,t in self.passwd.items():
@ -491,7 +479,7 @@ class userProfile(object):
del self.passwd[h]
try:
jsonoutput = json.dumps(self.passwd, indent=4)
except ValueError, e:
except ValueError as e:
raise e
with open(_datadir+"passwd.js", 'w') as fp:
fp.write(jsonoutput)
@ -511,19 +499,13 @@ class PesterProfileDB(dict):
if not os.path.exists(self.logpath):
os.makedirs(self.logpath)
try:
fp = open("%s/chums.js" % (self.logpath), 'r')
with open("%s/chums.js" % (self.logpath), 'r') as fp:
chumdict = json.load(fp)
fp.close()
except IOError:
except (IOError, ValueError):
# karxi: This code feels awfully familiar....
chumdict = {}
fp = open("%s/chums.js" % (self.logpath), 'w')
with open("%s/chums.js" % (self.logpath), 'w') as fp:
json.dump(chumdict, fp)
fp.close()
except ValueError:
chumdict = {}
fp = open("%s/chums.js" % (self.logpath), 'w')
json.dump(chumdict, fp)
fp.close()
u = []
for (handle, c) in chumdict.iteritems():
@ -542,11 +524,10 @@ class PesterProfileDB(dict):
def save(self):
try:
fp = open("%s/chums.js" % (self.logpath), 'w')
with open("%s/chums.js" % (self.logpath), 'w') as fp:
chumdict = dict([p.plaindict() for p in self.itervalues()])
json.dump(chumdict, fp)
fp.close()
except Exception, e:
except Exception as e:
raise e
def getColor(self, handle, default=None):
if not self.has_key(handle):
@ -598,9 +579,8 @@ class pesterTheme(dict):
self.name = name
try:
fp = open(self.path+"/style.js")
with open(self.path+"/style.js") as fp:
theme = json.load(fp, object_hook=self.pathHook)
fp.close()
except IOError:
theme = json.loads("{}")
self.update(theme)
@ -612,7 +592,7 @@ class pesterTheme(dict):
keys = key.split("/")
try:
v = dict.__getitem__(self, keys.pop(0))
except KeyError, e:
except KeyError as e:
if hasattr(self, 'inheritedTheme'):
return self.inheritedTheme[key]
if hasattr(self, 'defaultTheme'):
@ -622,7 +602,7 @@ class pesterTheme(dict):
for k in keys:
try:
v = v[k]
except KeyError, e:
except KeyError as e:
if hasattr(self, 'inheritedTheme'):
return self.inheritedTheme[key]
if hasattr(self, 'defaultTheme'):

View file

@ -64,7 +64,7 @@ class ScriptQuirks(object):
module = self.loadModule(name, filename)
if module is None:
continue
except Exception, e:
except Exception as e:
print "Error loading %s: %s (in quirks.py)" % (os.path.basename(name), e)
msgbox = QtGui.QMessageBox()
msgbox.setWindowTitle("Error!")

View file

@ -36,7 +36,7 @@ class MSPAChecker(QtGui.QWidget):
raise
if os.path.exists("status_old.pkl"):
os.remove("status_old.pkl")
except Exception, e:
except Exception as e:
print e
msg = QtGui.QMessageBox(self)
msg.setText("Problems writing save file.")