General cleanup. Stopped using older 'except Error, var' syntax.
This commit is contained in:
parent
e40aac88ac
commit
3a48cf204b
13 changed files with 168 additions and 143 deletions
28
TODO.mkdn
28
TODO.mkdn
|
@ -39,6 +39,32 @@ Features
|
||||||
* Overhaul debugging
|
* Overhaul debugging
|
||||||
* Make a console to display debug info without requiring us to run from console
|
* Make a console to display debug info without requiring us to run from console
|
||||||
* Debug generic.py's CaseInsensitiveDict/replace it with mine
|
* 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
|
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)
|
* +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)
|
* 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
|
* 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
|
Windows Bugs
|
||||||
------------
|
------------
|
||||||
|
|
2
convo.py
2
convo.py
|
@ -462,7 +462,7 @@ class PesterText(QtGui.QTextEdit):
|
||||||
else:
|
else:
|
||||||
self.sending.sendinglabel.setText("F41L3D: %s %s" % (response.status, response.reason))
|
self.sending.sendinglabel.setText("F41L3D: %s %s" % (response.status, response.reason))
|
||||||
hconn.close()
|
hconn.close()
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
self.sending.sendinglabel.setText("F41L3D: %s" % (e))
|
self.sending.sendinglabel.setText("F41L3D: %s" % (e))
|
||||||
del self.sending
|
del self.sending
|
||||||
|
|
||||||
|
|
|
@ -224,7 +224,7 @@ try:
|
||||||
print "Invalid input, try again"
|
print "Invalid input, try again"
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print ""
|
print ""
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
error = -1
|
error = -1
|
||||||
finally:
|
finally:
|
||||||
if error == -1:
|
if error == -1:
|
||||||
|
|
|
@ -2234,7 +2234,7 @@ def _parse_date(dateString):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
map(int, date9tuple)
|
map(int, date9tuple)
|
||||||
return date9tuple
|
return date9tuple
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
if _debug: sys.stderr.write('%s raised %s\n' % (handler.__name__, repr(e)))
|
if _debug: sys.stderr.write('%s raised %s\n' % (handler.__name__, repr(e)))
|
||||||
pass
|
pass
|
||||||
return None
|
return None
|
||||||
|
@ -2458,7 +2458,7 @@ def parse(url_file_stream_or_string, etag=None, modified=None, agent=None, refer
|
||||||
try:
|
try:
|
||||||
f = _open_resource(url_file_stream_or_string, etag, modified, agent, referrer, handlers)
|
f = _open_resource(url_file_stream_or_string, etag, modified, agent, referrer, handlers)
|
||||||
data = f.read()
|
data = f.read()
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
result['bozo'] = 1
|
result['bozo'] = 1
|
||||||
result['bozo_exception'] = e
|
result['bozo_exception'] = e
|
||||||
data = ''
|
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':
|
if gzip and f.headers.get('content-encoding', '') == 'gzip':
|
||||||
try:
|
try:
|
||||||
data = gzip.GzipFile(fileobj=_StringIO(data)).read()
|
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
|
# Some feeds claim to be gzipped but they're not, so
|
||||||
# we get garbage. Ideally, we should re-request the
|
# we get garbage. Ideally, we should re-request the
|
||||||
# feed without the 'Accept-encoding: gzip' header,
|
# 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':
|
elif zlib and f.headers.get('content-encoding', '') == 'deflate':
|
||||||
try:
|
try:
|
||||||
data = zlib.decompress(data, -zlib.MAX_WBITS)
|
data = zlib.decompress(data, -zlib.MAX_WBITS)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
result['bozo'] = 1
|
result['bozo'] = 1
|
||||||
result['bozo_exception'] = e
|
result['bozo_exception'] = e
|
||||||
data = ''
|
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'})
|
saxparser._ns_stack.append({'http://www.w3.org/XML/1998/namespace':'xml'})
|
||||||
try:
|
try:
|
||||||
saxparser.parse(source)
|
saxparser.parse(source)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
if _debug:
|
if _debug:
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_stack()
|
traceback.print_stack()
|
||||||
|
|
|
@ -204,7 +204,7 @@ class IRCClient:
|
||||||
logging.info('error: closing socket')
|
logging.info('error: closing socket')
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
raise se
|
raise se
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
logging.debug("other exception: %s" % e)
|
logging.debug("other exception: %s" % e)
|
||||||
raise e
|
raise e
|
||||||
else:
|
else:
|
||||||
|
@ -270,7 +270,7 @@ class IRCApp:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
clientdesc.con.next()
|
clientdesc.con.next()
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
logging.error('client error %s' % e)
|
logging.error('client error %s' % e)
|
||||||
logging.error(traceback.format_exc())
|
logging.error(traceback.format_exc())
|
||||||
if clientdesc.autoreconnect:
|
if clientdesc.autoreconnect:
|
||||||
|
|
|
@ -104,7 +104,7 @@ class CommandHandler(object):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
f(*args)
|
f(*args)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
logging.error('command raised %s' % e)
|
logging.error('command raised %s' % e)
|
||||||
logging.error(traceback.format_exc())
|
logging.error(traceback.format_exc())
|
||||||
raise CommandError(command)
|
raise CommandError(command)
|
||||||
|
@ -150,7 +150,7 @@ class DefaultBotCommandHandler(CommandHandler):
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
f = self.get(arg)
|
f = self.get(arg)
|
||||||
except CommandError, e:
|
except CommandError as e:
|
||||||
helpers.msg(self.client, dest, str(e))
|
helpers.msg(self.client, dest, str(e))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ class BotCommandHandler(DefaultCommandHandler):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.command_handler.run(command, prefix, dest, *arg)
|
self.command_handler.run(command, prefix, dest, *arg)
|
||||||
except CommandError, e:
|
except CommandError as e:
|
||||||
helpers.msg(self.client, dest, str(e))
|
helpers.msg(self.client, dest, str(e))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -220,7 +220,8 @@ kxpclexer = lexercon.Pesterchum()
|
||||||
def kxlexMsg(string):
|
def kxlexMsg(string):
|
||||||
# Do a bit of sanitization.
|
# Do a bit of sanitization.
|
||||||
msg = unicode(string)
|
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', ' ')
|
msg = msg.replace('\n', ' ').replace('\r', ' ')
|
||||||
# Something the original doesn't seem to have accounted for.
|
# Something the original doesn't seem to have accounted for.
|
||||||
# Replace tabs with 4 spaces.
|
# 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
|
Keep in mind that there's a little bit of magic involved in this at the
|
||||||
moment; some unsafe assumptions are made."""
|
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
|
# 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
|
# 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
|
# the start of the next line (or just keep a running line length
|
||||||
# total), and continue.
|
# total), and continue.
|
||||||
# N.B.: Keep the end tag length too. (+4 for each.)
|
# N.B.: Keep the end tag length too. (+4 for each.)
|
||||||
# Copy the list so we can't break anything.
|
# 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)
|
lexed = list(lexed)
|
||||||
working = []
|
working = []
|
||||||
output = []
|
output = []
|
||||||
|
@ -479,7 +490,7 @@ def kxsplitMsg(lexed, fmt="pchum", maxlen=None, debug=False):
|
||||||
if text_preproc:
|
if text_preproc:
|
||||||
# If we got here, it means we overflowed due to text - which
|
# If we got here, it means we overflowed due to text - which
|
||||||
# means we also split and added it to working. There's no
|
# 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.
|
# This could be handled with an elif chain, but eh.
|
||||||
continue
|
continue
|
||||||
# If we got here, it means we haven't done anything with 'msg' yet,
|
# 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.
|
# files for the original sentMessage variants.
|
||||||
|
|
||||||
if flavor is None:
|
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:
|
if text is None:
|
||||||
# Fetch the raw text from the input box.
|
# Fetch the raw text from the input box.
|
||||||
|
|
|
@ -15,19 +15,21 @@ reqmissing = []
|
||||||
optmissing = []
|
optmissing = []
|
||||||
try:
|
try:
|
||||||
from PyQt4 import QtGui, QtCore
|
from PyQt4 import QtGui, QtCore
|
||||||
except ImportError, e:
|
except ImportError as e:
|
||||||
module = str(e)
|
module = str(e)
|
||||||
if module.startswith("No module named ") or \
|
if module.startswith("No module named ") or \
|
||||||
module.startswith("cannot import name "):
|
module.startswith("cannot import name "):
|
||||||
reqmissing.append(module[module.rfind(" ")+1:])
|
reqmissing.append(module[module.rfind(" ")+1:])
|
||||||
else: print e
|
else: print e
|
||||||
|
del module
|
||||||
try:
|
try:
|
||||||
import pygame
|
import pygame
|
||||||
except ImportError, e:
|
except ImportError as e:
|
||||||
pygame = None
|
pygame = None
|
||||||
module = str(e)
|
module = str(e)
|
||||||
if module[:16] == "No module named ": optmissing.append(module[16:])
|
if module[:16] == "No module named ": optmissing.append(module[16:])
|
||||||
else: print e
|
else: print e
|
||||||
|
del module
|
||||||
if reqmissing:
|
if reqmissing:
|
||||||
print "ERROR: The following modules are required for Pesterchum to run and are missing on your system:"
|
print "ERROR: The following modules are required for Pesterchum to run and are missing on your system:"
|
||||||
for m in reqmissing: print "* "+m
|
for m in reqmissing: print "* "+m
|
||||||
|
@ -1022,10 +1024,10 @@ class PesterWindow(MovingWindow):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
themeChecker(self.theme)
|
themeChecker(self.theme)
|
||||||
except ThemeException, (inst):
|
except ThemeException as inst:
|
||||||
print "Caught: "+inst.parameter
|
print "Caught: " + inst.parameter
|
||||||
themeWarning = QtGui.QMessageBox(self)
|
themeWarning = QtGui.QMessageBox(self)
|
||||||
themeWarning.setText("Theme Error: %s" % (inst))
|
themeWarning.setText("Theme Error: %s" % inst)
|
||||||
themeWarning.exec_()
|
themeWarning.exec_()
|
||||||
self.theme = pesterTheme("pesterchum")
|
self.theme = pesterTheme("pesterchum")
|
||||||
|
|
||||||
|
@ -1679,15 +1681,15 @@ class PesterWindow(MovingWindow):
|
||||||
else:
|
else:
|
||||||
sound.setVolume(vol)
|
sound.setVolume(vol)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
print "Couldn't set volumme: {}".format(err)
|
print "Couldn't set volume: {}".format(err)
|
||||||
|
|
||||||
def changeTheme(self, theme):
|
def changeTheme(self, theme):
|
||||||
# check theme
|
# check theme
|
||||||
try:
|
try:
|
||||||
themeChecker(theme)
|
themeChecker(theme)
|
||||||
except ThemeException, (inst):
|
except ThemeException as inst:
|
||||||
themeWarning = QtGui.QMessageBox(self)
|
themeWarning = QtGui.QMessageBox(self)
|
||||||
themeWarning.setText("Theme Error: %s" % (inst))
|
themeWarning.setText("Theme Error: %s" % inst)
|
||||||
themeWarning.exec_()
|
themeWarning.exec_()
|
||||||
theme = pesterTheme("pesterchum")
|
theme = pesterTheme("pesterchum")
|
||||||
return
|
return
|
||||||
|
@ -2521,7 +2523,7 @@ class PesterWindow(MovingWindow):
|
||||||
newmodes = self.optionmenu.modechange.text()
|
newmodes = self.optionmenu.modechange.text()
|
||||||
if newmodes:
|
if newmodes:
|
||||||
self.setChannelMode.emit(self.profile().handle, newmodes, "")
|
self.setChannelMode.emit(self.profile().handle, newmodes, "")
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
logging.error(e)
|
logging.error(e)
|
||||||
finally:
|
finally:
|
||||||
self.optionmenu = None
|
self.optionmenu = None
|
||||||
|
@ -2560,7 +2562,7 @@ class PesterWindow(MovingWindow):
|
||||||
if override or themename != self.theme.name:
|
if override or themename != self.theme.name:
|
||||||
try:
|
try:
|
||||||
self.changeTheme(pesterTheme(themename))
|
self.changeTheme(pesterTheme(themename))
|
||||||
except ValueError, e:
|
except ValueError as e:
|
||||||
themeWarning = QtGui.QMessageBox(self)
|
themeWarning = QtGui.QMessageBox(self)
|
||||||
themeWarning.setText("Theme Error: %s" % (e))
|
themeWarning.setText("Theme Error: %s" % (e))
|
||||||
themeWarning.exec_()
|
themeWarning.exec_()
|
||||||
|
|
|
@ -252,6 +252,12 @@ class Pesterchum(Lexer):
|
||||||
_ctag_end = re.compile(r"</c>", flags=re.I)
|
_ctag_end = re.compile(r"</c>", flags=re.I)
|
||||||
_mecmdre = re.compile(r"^(/me|PESTERCHUM:ME)(\S*)")
|
_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):
|
def lex(self, string):
|
||||||
lexlist = [
|
lexlist = [
|
||||||
##(mecmd, self._mecmdre),
|
##(mecmd, self._mecmdre),
|
||||||
|
|
108
pnc/unicolor.py
108
pnc/unicolor.py
|
@ -37,27 +37,6 @@ class Color(object):
|
||||||
# TODO: color_for_name()
|
# TODO: color_for_name()
|
||||||
# TODO: Split __init__, partly using __new__, so the former just has to do
|
# TODO: Split __init__, partly using __new__, so the former just has to do
|
||||||
# conversions
|
# 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):
|
def __init__(self, *args, **kwargs):
|
||||||
self.ccode = ''
|
self.ccode = ''
|
||||||
self.closest_name = self.name = None
|
self.closest_name = self.name = None
|
||||||
|
@ -284,37 +263,47 @@ class Color(object):
|
||||||
def hexstr_to_rgb(cls, hexstr):
|
def hexstr_to_rgb(cls, hexstr):
|
||||||
hexstr = cls.sanitize_hex(hexstr)
|
hexstr = cls.sanitize_hex(hexstr)
|
||||||
hexstr = hexstr.lstrip('#')
|
hexstr = hexstr.lstrip('#')
|
||||||
# This is ugly, but the purpose is simple and it's accomplished in a
|
if len(hexstr) == 3:
|
||||||
# single line...it just runs through the string, picking two characters
|
# NOTE: This will presently never happen, due to the way
|
||||||
# at a time and converting them from hex values to ints.
|
# sanitize_hex works.
|
||||||
result = tuple(int(hexstr[i:i+2], 16) for i in range(len(hexstr))[::2])
|
# 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
|
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
|
@staticmethod
|
||||||
def rgb_to_hexstr(red, green, blue):
|
def rgb_to_hexstr(red, green, blue, compress=False):
|
||||||
rgb = [red, green, blue]
|
rgb = [red, green, blue]
|
||||||
rgb = map(abs, rgb)
|
rgb = map(abs, rgb)
|
||||||
# Preemptively add the '#' to our result
|
result = []
|
||||||
result = ['#']
|
|
||||||
for c in rgb:
|
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
|
c = "%02X" % c
|
||||||
# Append to our result
|
# Append to our result
|
||||||
result.append(c)
|
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
|
# Join and return the result
|
||||||
return ''.join(result)
|
return '#' + ''.join(result)
|
||||||
|
|
||||||
# These next two are from http://www.easyrgb.com/index.php?X=MATH
|
# These next two are from http://www.easyrgb.com/index.php?X=MATH
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -355,37 +344,46 @@ class Color(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def reduce_hexstr(hexstr):
|
def reduce_hexstr(hexstr):
|
||||||
|
"""Attempt to reduce a six-character hexadecimal color code down to a
|
||||||
|
four-character one."""
|
||||||
orig = hexstr
|
orig = hexstr
|
||||||
hexstr = hexstr.lstrip('#')
|
hexstr = hexstr.lstrip('#')
|
||||||
lhexstr = hexstr.lower()
|
|
||||||
strlen = len(hexstr)
|
strlen = len(hexstr)
|
||||||
working = ['#']
|
h = hexstr.upper()
|
||||||
for i in range(strlen)[::2]:
|
for i in range(0, strlen, 2):
|
||||||
if lhexstr[i] == lhexstr[i+1]:
|
if h[i] != h[i+1]:
|
||||||
# The two characters fetched are the same, so we can reduce
|
# We found a match that wouldn't work; give back the old value.
|
||||||
working.append(hexstr[i])
|
|
||||||
else:
|
|
||||||
# The two characters differ, so we can't actually reduce this
|
|
||||||
# string at all; just return the original
|
|
||||||
return orig
|
return orig
|
||||||
# If we got here, we successfully reduced
|
else:
|
||||||
return ''.join(working)
|
# All of these can be reduced; do so and return.
|
||||||
|
return '#' + hexstr[::2]
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def sanitize_hex(hexstr):
|
def sanitize_hex(hexstr):
|
||||||
|
orig = hexstr
|
||||||
hexstr = hexstr.upper()
|
hexstr = hexstr.upper()
|
||||||
# We don't need the leading hash mark for now
|
# We don't need the leading hash mark for now
|
||||||
hexstr = hexstr.lstrip('#')
|
hexstr = hexstr.lstrip('#')
|
||||||
strlen = len(hexstr)
|
strlen = len(hexstr)
|
||||||
if strlen == 6:
|
if strlen == 6:
|
||||||
return '#' + hexstr
|
# We just need to test this for validity. Fall through to the end.
|
||||||
|
pass
|
||||||
elif strlen == 3:
|
elif strlen == 3:
|
||||||
# We have a short (CSS style) code; duplicate all of the characters
|
# We have a short (CSS style) code; duplicate all of the characters
|
||||||
hexstr = [c + c for c in hexstr]
|
hexstr = [c + c for c in hexstr]
|
||||||
hexstr = ''.join(hexstr)
|
hexstr = ''.join(hexstr)
|
||||||
return '#' + hexstr
|
else:
|
||||||
# Should probably error out, but that can wait until later
|
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
|
return '#' + hexstr
|
||||||
|
|
||||||
def to_cielab_tuple(self):
|
def to_cielab_tuple(self):
|
||||||
|
|
102
profile.py
102
profile.py
|
@ -97,9 +97,8 @@ class userConfig(object):
|
||||||
self.NEWCONVO = 8
|
self.NEWCONVO = 8
|
||||||
self.INITIALS = 16
|
self.INITIALS = 16
|
||||||
self.filename = _datadir+"pesterchum.js"
|
self.filename = _datadir+"pesterchum.js"
|
||||||
fp = open(self.filename)
|
with open(self.filename) as fp:
|
||||||
self.config = json.load(fp)
|
self.config = json.load(fp)
|
||||||
fp.close()
|
|
||||||
if self.config.has_key("defaultprofile"):
|
if self.config.has_key("defaultprofile"):
|
||||||
self.userprofile = userProfile(self.config["defaultprofile"])
|
self.userprofile = userProfile(self.config["defaultprofile"])
|
||||||
else:
|
else:
|
||||||
|
@ -110,28 +109,21 @@ class userConfig(object):
|
||||||
if not os.path.exists(self.logpath):
|
if not os.path.exists(self.logpath):
|
||||||
os.makedirs(self.logpath)
|
os.makedirs(self.logpath)
|
||||||
try:
|
try:
|
||||||
fp = open("%s/groups.js" % (self.logpath), 'r')
|
with open("%s/groups.js" % (self.logpath), 'r') as fp:
|
||||||
self.groups = json.load(fp)
|
self.groups = json.load(fp)
|
||||||
fp.close()
|
except (IOError, ValueError):
|
||||||
except IOError:
|
|
||||||
self.groups = {}
|
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)
|
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):
|
def chums(self):
|
||||||
if not self.config.has_key('chums'):
|
if not self.config.has_key('chums'):
|
||||||
self.set("chums", [])
|
self.set("chums", [])
|
||||||
return self.config.get('chums', [])
|
return self.config.get('chums', [])
|
||||||
def setChums(self, newchums):
|
def setChums(self, newchums):
|
||||||
fp = open(self.filename) # what if we have two clients open??
|
with open(self.filename) as fp:
|
||||||
newconfig = json.load(fp)
|
# what if we have two clients open??
|
||||||
fp.close()
|
newconfig = json.load(fp)
|
||||||
oldchums = newconfig['chums']
|
oldchums = newconfig['chums']
|
||||||
# Time to merge these two! :OOO
|
# Time to merge these two! :OOO
|
||||||
for c in list(set(oldchums) - set(newchums)):
|
for c in list(set(oldchums) - set(newchums)):
|
||||||
|
@ -225,9 +217,9 @@ class userConfig(object):
|
||||||
return self.config.get('ghostchum', False)
|
return self.config.get('ghostchum', False)
|
||||||
def addChum(self, chum):
|
def addChum(self, chum):
|
||||||
if chum.handle not in self.chums():
|
if chum.handle not in self.chums():
|
||||||
fp = open(self.filename) # what if we have two clients open??
|
with open(self.filename) as fp:
|
||||||
newconfig = json.load(fp)
|
# what if we have two clients open??
|
||||||
fp.close()
|
newconfig = json.load(fp)
|
||||||
newchums = newconfig['chums'] + [chum.handle]
|
newchums = newconfig['chums'] + [chum.handle]
|
||||||
self.set("chums", newchums)
|
self.set("chums", newchums)
|
||||||
def removeChum(self, chum):
|
def removeChum(self, chum):
|
||||||
|
@ -285,11 +277,10 @@ class userConfig(object):
|
||||||
self.groups['groups'] = groups
|
self.groups['groups'] = groups
|
||||||
try:
|
try:
|
||||||
jsonoutput = json.dumps(self.groups)
|
jsonoutput = json.dumps(self.groups)
|
||||||
except ValueError, e:
|
except ValueError as e:
|
||||||
raise 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.write(jsonoutput)
|
||||||
fp.close()
|
|
||||||
|
|
||||||
def server(self):
|
def server(self):
|
||||||
if hasattr(self.parent, 'serverOverride'):
|
if hasattr(self.parent, 'serverOverride'):
|
||||||
|
@ -319,11 +310,10 @@ class userConfig(object):
|
||||||
self.config[item] = setting
|
self.config[item] = setting
|
||||||
try:
|
try:
|
||||||
jsonoutput = json.dumps(self.config)
|
jsonoutput = json.dumps(self.config)
|
||||||
except ValueError, e:
|
except ValueError as e:
|
||||||
raise e
|
raise e
|
||||||
fp = open(self.filename, 'w')
|
with open(self.filename, 'w') as fp:
|
||||||
fp.write(jsonoutput)
|
fp.write(jsonoutput)
|
||||||
fp.close()
|
|
||||||
def availableThemes(self):
|
def availableThemes(self):
|
||||||
themes = []
|
themes = []
|
||||||
# Load user themes.
|
# Load user themes.
|
||||||
|
@ -372,12 +362,11 @@ class userProfile(object):
|
||||||
self.mentions = []
|
self.mentions = []
|
||||||
self.autojoins = []
|
self.autojoins = []
|
||||||
else:
|
else:
|
||||||
fp = open("%s/%s.js" % (self.profiledir, user))
|
with open("%s/%s.js" % (self.profiledir, user)) as fp:
|
||||||
self.userprofile = json.load(fp)
|
self.userprofile = json.load(fp)
|
||||||
fp.close()
|
|
||||||
try:
|
try:
|
||||||
self.theme = pesterTheme(self.userprofile["theme"])
|
self.theme = pesterTheme(self.userprofile["theme"])
|
||||||
except ValueError, e:
|
except ValueError:
|
||||||
self.theme = pesterTheme("pesterchum")
|
self.theme = pesterTheme("pesterchum")
|
||||||
self.lastmood = self.userprofile.get('lastmood', self.theme["main/defaultmood"])
|
self.lastmood = self.userprofile.get('lastmood', self.theme["main/defaultmood"])
|
||||||
self.chat = PesterProfile(self.userprofile["handle"],
|
self.chat = PesterProfile(self.userprofile["handle"],
|
||||||
|
@ -402,7 +391,7 @@ class userProfile(object):
|
||||||
try:
|
try:
|
||||||
with open(_datadir+"passwd.js") as fp:
|
with open(_datadir+"passwd.js") as fp:
|
||||||
self.passwd = json.load(fp)
|
self.passwd = json.load(fp)
|
||||||
except Exception, e:
|
except:
|
||||||
self.passwd = {}
|
self.passwd = {}
|
||||||
self.autoidentify = False
|
self.autoidentify = False
|
||||||
self.nickservpass = ""
|
self.nickservpass = ""
|
||||||
|
@ -479,11 +468,10 @@ class userProfile(object):
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
jsonoutput = json.dumps(self.userprofile)
|
jsonoutput = json.dumps(self.userprofile)
|
||||||
except ValueError, e:
|
except ValueError as e:
|
||||||
raise 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.write(jsonoutput)
|
||||||
fp.close()
|
|
||||||
def saveNickServPass(self):
|
def saveNickServPass(self):
|
||||||
# remove profiles with no passwords
|
# remove profiles with no passwords
|
||||||
for h,t in self.passwd.items():
|
for h,t in self.passwd.items():
|
||||||
|
@ -491,7 +479,7 @@ class userProfile(object):
|
||||||
del self.passwd[h]
|
del self.passwd[h]
|
||||||
try:
|
try:
|
||||||
jsonoutput = json.dumps(self.passwd, indent=4)
|
jsonoutput = json.dumps(self.passwd, indent=4)
|
||||||
except ValueError, e:
|
except ValueError as e:
|
||||||
raise e
|
raise e
|
||||||
with open(_datadir+"passwd.js", 'w') as fp:
|
with open(_datadir+"passwd.js", 'w') as fp:
|
||||||
fp.write(jsonoutput)
|
fp.write(jsonoutput)
|
||||||
|
@ -511,19 +499,13 @@ class PesterProfileDB(dict):
|
||||||
if not os.path.exists(self.logpath):
|
if not os.path.exists(self.logpath):
|
||||||
os.makedirs(self.logpath)
|
os.makedirs(self.logpath)
|
||||||
try:
|
try:
|
||||||
fp = open("%s/chums.js" % (self.logpath), 'r')
|
with open("%s/chums.js" % (self.logpath), 'r') as fp:
|
||||||
chumdict = json.load(fp)
|
chumdict = json.load(fp)
|
||||||
fp.close()
|
except (IOError, ValueError):
|
||||||
except IOError:
|
# karxi: This code feels awfully familiar....
|
||||||
chumdict = {}
|
chumdict = {}
|
||||||
fp = open("%s/chums.js" % (self.logpath), 'w')
|
with open("%s/chums.js" % (self.logpath), 'w') as fp:
|
||||||
json.dump(chumdict, 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 = []
|
u = []
|
||||||
for (handle, c) in chumdict.iteritems():
|
for (handle, c) in chumdict.iteritems():
|
||||||
|
@ -542,11 +524,10 @@ class PesterProfileDB(dict):
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
try:
|
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()])
|
chumdict = dict([p.plaindict() for p in self.itervalues()])
|
||||||
json.dump(chumdict, fp)
|
json.dump(chumdict, fp)
|
||||||
fp.close()
|
except Exception as e:
|
||||||
except Exception, e:
|
|
||||||
raise e
|
raise e
|
||||||
def getColor(self, handle, default=None):
|
def getColor(self, handle, default=None):
|
||||||
if not self.has_key(handle):
|
if not self.has_key(handle):
|
||||||
|
@ -598,9 +579,8 @@ class pesterTheme(dict):
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
try:
|
try:
|
||||||
fp = open(self.path+"/style.js")
|
with open(self.path+"/style.js") as fp:
|
||||||
theme = json.load(fp, object_hook=self.pathHook)
|
theme = json.load(fp, object_hook=self.pathHook)
|
||||||
fp.close()
|
|
||||||
except IOError:
|
except IOError:
|
||||||
theme = json.loads("{}")
|
theme = json.loads("{}")
|
||||||
self.update(theme)
|
self.update(theme)
|
||||||
|
@ -612,7 +592,7 @@ class pesterTheme(dict):
|
||||||
keys = key.split("/")
|
keys = key.split("/")
|
||||||
try:
|
try:
|
||||||
v = dict.__getitem__(self, keys.pop(0))
|
v = dict.__getitem__(self, keys.pop(0))
|
||||||
except KeyError, e:
|
except KeyError as e:
|
||||||
if hasattr(self, 'inheritedTheme'):
|
if hasattr(self, 'inheritedTheme'):
|
||||||
return self.inheritedTheme[key]
|
return self.inheritedTheme[key]
|
||||||
if hasattr(self, 'defaultTheme'):
|
if hasattr(self, 'defaultTheme'):
|
||||||
|
@ -622,7 +602,7 @@ class pesterTheme(dict):
|
||||||
for k in keys:
|
for k in keys:
|
||||||
try:
|
try:
|
||||||
v = v[k]
|
v = v[k]
|
||||||
except KeyError, e:
|
except KeyError as e:
|
||||||
if hasattr(self, 'inheritedTheme'):
|
if hasattr(self, 'inheritedTheme'):
|
||||||
return self.inheritedTheme[key]
|
return self.inheritedTheme[key]
|
||||||
if hasattr(self, 'defaultTheme'):
|
if hasattr(self, 'defaultTheme'):
|
||||||
|
|
|
@ -64,7 +64,7 @@ class ScriptQuirks(object):
|
||||||
module = self.loadModule(name, filename)
|
module = self.loadModule(name, filename)
|
||||||
if module is None:
|
if module is None:
|
||||||
continue
|
continue
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
print "Error loading %s: %s (in quirks.py)" % (os.path.basename(name), e)
|
print "Error loading %s: %s (in quirks.py)" % (os.path.basename(name), e)
|
||||||
msgbox = QtGui.QMessageBox()
|
msgbox = QtGui.QMessageBox()
|
||||||
msgbox.setWindowTitle("Error!")
|
msgbox.setWindowTitle("Error!")
|
||||||
|
|
|
@ -36,7 +36,7 @@ class MSPAChecker(QtGui.QWidget):
|
||||||
raise
|
raise
|
||||||
if os.path.exists("status_old.pkl"):
|
if os.path.exists("status_old.pkl"):
|
||||||
os.remove("status_old.pkl")
|
os.remove("status_old.pkl")
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
print e
|
print e
|
||||||
msg = QtGui.QMessageBox(self)
|
msg = QtGui.QMessageBox(self)
|
||||||
msg.setText("Problems writing save file.")
|
msg.setText("Problems writing save file.")
|
||||||
|
|
Loading…
Reference in a new issue