From 50fe275870cdbd78660af347070f62f2049d5bf6 Mon Sep 17 00:00:00 2001 From: mutantmonkey Date: Thu, 22 Sep 2011 14:17:27 -0400 Subject: [PATCH] Port to python3, fix ssl support --- __init__.py | 8 +- bot.py | 371 ++++++++++++++++++++-------------------- irc.py | 332 ++++++++++++++++++----------------- modules/8ball.py | 2 +- modules/admin.py | 2 +- modules/archwiki.py | 8 +- modules/botfun.py | 2 +- modules/botsnack.py | 10 +- modules/calc.py | 22 +-- modules/chillmeter.py | 2 +- modules/clock.py | 14 +- modules/codepoints.py | 18 +- modules/etymology.py | 5 +- modules/head.py | 44 ++--- modules/hs.py | 4 +- modules/info.py | 14 +- modules/lastfm.py | 19 +- modules/mylife.py | 25 ++- modules/nsfw.py | 2 +- modules/oblique.py | 14 +- modules/ping.py | 2 +- modules/reload.py | 4 +- modules/remind.py | 12 +- modules/search.py | 19 +- modules/seen.py | 6 +- modules/slogan.py | 4 +- modules/startup.py | 2 +- modules/tell.py | 16 +- modules/tfw.py | 10 +- modules/translate.py | 17 +- modules/uncyclopedia.py | 30 ++-- modules/validate.py | 6 +- modules/vtluugwiki.py | 8 +- modules/wargame.py | 15 +- modules/weather.py | 42 ++--- modules/wikipedia.py | 8 +- modules/wiktionary.py | 10 +- opt/freenode.py | 2 +- phenny | 30 ++-- tools.py | 2 +- web.py | 87 +++++----- 41 files changed, 628 insertions(+), 622 deletions(-) diff --git a/__init__.py b/__init__.py index 185973a..ca35fb0 100755 --- a/__init__.py +++ b/__init__.py @@ -37,8 +37,8 @@ def run_phenny(config): p.run(config.host, config.port, config.ssl, config.ipv6) try: Watcher() - except Exception, e: - print >> sys.stderr, 'Warning:', e, '(in __init__.py)' + except Exception as e: + print('Warning:', e, '(in __init__.py)', file=sys.stderr) while True: try: connect(config) @@ -49,7 +49,7 @@ def run_phenny(config): break warning = 'Warning: Disconnected. Reconnecting in %s seconds...' % delay - print >> sys.stderr, warning + print(warning, file=sys.stderr) time.sleep(delay) def run(config): @@ -59,4 +59,4 @@ def run(config): else: t.start() if __name__ == '__main__': - print __doc__ + print(__doc__) diff --git a/bot.py b/bot.py index ebafa68..b794913 100755 --- a/bot.py +++ b/bot.py @@ -13,222 +13,225 @@ import irc home = os.getcwd() def decode(bytes): - try: text = bytes.decode('utf-8') - except UnicodeDecodeError: - try: text = bytes.decode('iso-8859-1') - except UnicodeDecodeError: - text = bytes.decode('cp1252') - return text + if type(bytes) == str: + return bytes + try: text = bytes.decode('utf-8') + except UnicodeDecodeError: + try: text = bytes.decode('iso-8859-1') + except UnicodeDecodeError: + text = bytes.decode('cp1252') + return text class Phenny(irc.Bot): - def __init__(self, config): - args = (config.nick, config.name, config.channels, config.password) - irc.Bot.__init__(self, *args) - self.config = config - self.doc = {} - self.stats = {} - self.setup() + def __init__(self, config): + args = (config.nick, config.name, config.channels, config.password) + irc.Bot.__init__(self, *args) + self.config = config + self.doc = {} + self.stats = {} + self.setup() - def setup(self): - self.variables = {} + def setup(self): + self.variables = {} - filenames = [] - if not hasattr(self.config, 'enable'): - for fn in os.listdir(os.path.join(home, 'modules')): - if fn.endswith('.py') and not fn.startswith('_'): - filenames.append(os.path.join(home, 'modules', fn)) - else: - for fn in self.config.enable: - filenames.append(os.path.join(home, 'modules', fn + '.py')) + filenames = [] + if not hasattr(self.config, 'enable'): + for fn in os.listdir(os.path.join(home, 'modules')): + if fn.endswith('.py') and not fn.startswith('_'): + filenames.append(os.path.join(home, 'modules', fn)) + else: + for fn in self.config.enable: + filenames.append(os.path.join(home, 'modules', fn + '.py')) - if hasattr(self.config, 'extra'): - for fn in self.config.extra: - if os.path.isfile(fn): - filenames.append(fn) - elif os.path.isdir(fn): - for n in os.listdir(fn): - if n.endswith('.py') and not n.startswith('_'): - filenames.append(os.path.join(fn, n)) + if hasattr(self.config, 'extra'): + for fn in self.config.extra: + if os.path.isfile(fn): + filenames.append(fn) + elif os.path.isdir(fn): + for n in os.listdir(fn): + if n.endswith('.py') and not n.startswith('_'): + filenames.append(os.path.join(fn, n)) - modules = [] - excluded_modules = getattr(self.config, 'exclude', []) - for filename in filenames: - name = os.path.basename(filename)[:-3] - if name in excluded_modules: continue - # if name in sys.modules: - # del sys.modules[name] - try: module = imp.load_source(name, filename) - except Exception, e: - print >> sys.stderr, "Error loading %s: %s (in bot.py)" % (name, e) - else: - if hasattr(module, 'setup'): - module.setup(self) - self.register(vars(module)) - modules.append(name) + modules = [] + excluded_modules = getattr(self.config, 'exclude', []) + for filename in filenames: + name = os.path.basename(filename)[:-3] + if name in excluded_modules: continue + # if name in sys.modules: + # del sys.modules[name] + try: module = imp.load_source(name, filename) + except Exception as e: + print("Error loading %s: %s (in bot.py)" % (name, e), file=sys.stderr) + else: + if hasattr(module, 'setup'): + module.setup(self) + self.register(vars(module)) + modules.append(name) - if modules: - print >> sys.stderr, 'Registered modules:', ', '.join(modules) - else: print >> sys.stderr, "Warning: Couldn't find any modules" + if modules: + print('Registered modules:', ', '.join(modules), file=sys.stderr) + else: print("Warning: Couldn't find any modules", file=sys.stderr) - self.bind_commands() + self.bind_commands() - def register(self, variables): - # This is used by reload.py, hence it being methodised - for name, obj in variables.iteritems(): - if hasattr(obj, 'commands') or hasattr(obj, 'rule'): - self.variables[name] = obj + def register(self, variables): + # This is used by reload.py, hence it being methodised + for name, obj in variables.items(): + if hasattr(obj, 'commands') or hasattr(obj, 'rule'): + self.variables[name] = obj - def bind_commands(self): - self.commands = {'high': {}, 'medium': {}, 'low': {}} - - def bind(self, priority, regexp, func): - print priority, regexp.pattern.encode('utf-8'), func - # register documentation - if not hasattr(func, 'name'): - func.name = func.__name__ - if func.__doc__: - if hasattr(func, 'example'): - example = func.example - example = example.replace('$nickname', self.nick) - else: example = None - self.doc[func.name] = (func.__doc__, example) - self.commands[priority].setdefault(regexp, []).append(func) + def bind_commands(self): + self.commands = {'high': {}, 'medium': {}, 'low': {}} + + def bind(self, priority, regexp, func): + print(priority, regexp.pattern.encode('utf-8'), func) + # register documentation + if not hasattr(func, 'name'): + func.name = func.__name__ + if func.__doc__: + if hasattr(func, 'example'): + example = func.example + example = example.replace('$nickname', self.nick) + else: example = None + self.doc[func.name] = (func.__doc__, example) + self.commands[priority].setdefault(regexp, []).append(func) - def sub(pattern, self=self): - # These replacements have significant order - pattern = pattern.replace('$nickname', re.escape(self.nick)) - return pattern.replace('$nick', r'%s[,:] +' % re.escape(self.nick)) + def sub(pattern, self=self): + # These replacements have significant order + pattern = pattern.replace('$nickname', re.escape(self.nick)) + return pattern.replace('$nick', r'%s[,:] +' % re.escape(self.nick)) - for name, func in self.variables.iteritems(): - # print name, func - if not hasattr(func, 'priority'): - func.priority = 'medium' + for name, func in self.variables.items(): + # print name, func + if not hasattr(func, 'priority'): + func.priority = 'medium' - if not hasattr(func, 'thread'): - func.thread = True + if not hasattr(func, 'thread'): + func.thread = True - if not hasattr(func, 'event'): - func.event = 'PRIVMSG' - else: func.event = func.event.upper() + if not hasattr(func, 'event'): + func.event = 'PRIVMSG' + else: func.event = func.event.upper() - if hasattr(func, 'rule'): - if isinstance(func.rule, str): - pattern = sub(func.rule) - regexp = re.compile(pattern) - bind(self, func.priority, regexp, func) + if hasattr(func, 'rule'): + if isinstance(func.rule, str): + pattern = sub(func.rule) + regexp = re.compile(pattern) + bind(self, func.priority, regexp, func) - if isinstance(func.rule, tuple): - # 1) e.g. ('$nick', '(.*)') - if len(func.rule) == 2 and isinstance(func.rule[0], str): - prefix, pattern = func.rule - prefix = sub(prefix) - regexp = re.compile(prefix + pattern) - bind(self, func.priority, regexp, func) + if isinstance(func.rule, tuple): + # 1) e.g. ('$nick', '(.*)') + if len(func.rule) == 2 and isinstance(func.rule[0], str): + prefix, pattern = func.rule + prefix = sub(prefix) + regexp = re.compile(prefix + pattern) + bind(self, func.priority, regexp, func) - # 2) e.g. (['p', 'q'], '(.*)') - elif len(func.rule) == 2 and isinstance(func.rule[0], list): - prefix = self.config.prefix - commands, pattern = func.rule - for command in commands: - command = r'(%s)\b(?: +(?:%s))?' % (command, pattern) - regexp = re.compile(prefix + command) - bind(self, func.priority, regexp, func) + # 2) e.g. (['p', 'q'], '(.*)') + elif len(func.rule) == 2 and isinstance(func.rule[0], list): + prefix = self.config.prefix + commands, pattern = func.rule + for command in commands: + command = r'(%s)\b(?: +(?:%s))?' % (command, pattern) + regexp = re.compile(prefix + command) + bind(self, func.priority, regexp, func) - # 3) e.g. ('$nick', ['p', 'q'], '(.*)') - elif len(func.rule) == 3: - prefix, commands, pattern = func.rule - prefix = sub(prefix) - for command in commands: - command = r'(%s) +' % command - regexp = re.compile(prefix + command + pattern) - bind(self, func.priority, regexp, func) + # 3) e.g. ('$nick', ['p', 'q'], '(.*)') + elif len(func.rule) == 3: + prefix, commands, pattern = func.rule + prefix = sub(prefix) + for command in commands: + command = r'(%s) +' % command + regexp = re.compile(prefix + command + pattern) + bind(self, func.priority, regexp, func) - if hasattr(func, 'commands'): - for command in func.commands: - template = r'^%s(%s)(?: +(.*))?$' - pattern = template % (self.config.prefix, command) - regexp = re.compile(pattern) - bind(self, func.priority, regexp, func) + if hasattr(func, 'commands'): + for command in func.commands: + template = r'^%s(%s)(?: +(.*))?$' + pattern = template % (self.config.prefix, command) + regexp = re.compile(pattern) + bind(self, func.priority, regexp, func) - def wrapped(self, origin, text, match): - class PhennyWrapper(object): - def __init__(self, phenny): - self.bot = phenny + def wrapped(self, origin, text, match): + class PhennyWrapper(object): + def __init__(self, phenny): + self.bot = phenny - def __getattr__(self, attr): - sender = origin.sender or text - if attr == 'reply': - return (lambda msg: - self.bot.msg(sender, origin.nick + ': ' + msg)) - elif attr == 'say': - return lambda msg: self.bot.msg(sender, msg) - elif attr == 'do': - return lambda msg: self.bot.action(sender, msg) - return getattr(self.bot, attr) + def __getattr__(self, attr): + sender = origin.sender or text + if attr == 'reply': + return (lambda msg: + self.bot.msg(sender, origin.nick + ': ' + msg)) + elif attr == 'say': + return lambda msg: self.bot.msg(sender, msg) + elif attr == 'do': + return lambda msg: self.bot.action(sender, msg) + return getattr(self.bot, attr) - return PhennyWrapper(self) + return PhennyWrapper(self) - def input(self, origin, text, bytes, match, event, args): - class CommandInput(unicode): - def __new__(cls, text, origin, bytes, match, event, args): - s = unicode.__new__(cls, text) - s.sender = origin.sender - s.nick = origin.nick - s.event = event - s.bytes = bytes - s.match = match - s.group = match.group - s.groups = match.groups - s.args = args - s.admin = origin.nick in self.config.admins - s.owner = origin.nick == self.config.owner - return s + def input(self, origin, text, bytes, match, event, args): + class CommandInput(str): + def __new__(cls, text, origin, bytes, match, event, args): + s = str.__new__(cls, text) + s.sender = decode(origin.sender) + s.nick = decode(origin.nick) + s.event = event + s.bytes = bytes + s.match = match + s.group = match.group + s.groups = match.groups + s.args = args + s.admin = self.nick in self.config.admins + s.owner = self.nick == self.config.owner + return s - return CommandInput(text, origin, bytes, match, event, args) + return CommandInput(text, origin, bytes, match, event, args) - def call(self, func, origin, phenny, input): - try: func(phenny, input) - except Exception, e: - self.error(origin) + def call(self, func, origin, phenny, input): + try: func(phenny, input) + except Exception as e: + self.error(origin) - def limit(self, origin, func): - if origin.sender and origin.sender.startswith('#'): - if hasattr(self.config, 'limit'): - limits = self.config.limit.get(origin.sender) - if limits and (func.__module__ not in limits): - return True - return False + def limit(self, origin, func): + if origin.sender and origin.sender.startswith(b'#'): + if hasattr(self.config, 'limit'): + limits = self.config.limit.get(origin.sender) + if limits and (func.__module__ not in limits): + return True + return False - def dispatch(self, origin, args): - bytes, event, args = args[0], args[1], args[2:] - text = decode(bytes) + def dispatch(self, origin, args): + bytes, event, args = args[0], args[1], args[2:] + text = decode(bytes) + event = decode(event) - if origin.nick in self.config.ignore: - return + if origin.nick in self.config.ignore: + return - for priority in ('high', 'medium', 'low'): - items = self.commands[priority].items() - for regexp, funcs in items: - for func in funcs: - if event != func.event: continue + for priority in ('high', 'medium', 'low'): + items = list(self.commands[priority].items()) + for regexp, funcs in items: + for func in funcs: + if event != func.event: continue - match = regexp.match(text) - if match: - if self.limit(origin, func): continue + match = regexp.match(text) + if match: + if self.limit(origin, func): continue - phenny = self.wrapped(origin, text, match) - input = self.input(origin, text, bytes, match, event, args) + phenny = self.wrapped(origin, text, match) + input = self.input(origin, text, bytes, match, event, args) - if func.thread: - targs = (func, origin, phenny, input) - t = threading.Thread(target=self.call, args=targs) - t.start() - else: self.call(func, origin, phenny, input) + if func.thread: + targs = (func, origin, phenny, input) + t = threading.Thread(target=self.call, args=targs) + t.start() + else: self.call(func, origin, phenny, input) - for source in [origin.sender, origin.nick]: - try: self.stats[(func.name, source)] += 1 - except KeyError: - self.stats[(func.name, source)] = 1 + for source in [origin.sender, origin.nick]: + try: self.stats[(func.name, source)] += 1 + except KeyError: + self.stats[(func.name, source)] = 1 if __name__ == '__main__': - print __doc__ + print(__doc__) diff --git a/irc.py b/irc.py index 0c1ce2c..3a6ce19 100755 --- a/irc.py +++ b/irc.py @@ -9,204 +9,216 @@ http://inamidst.com/phenny/ import sys, re, time, traceback import socket, asyncore, asynchat +import ssl class Origin(object): - source = re.compile(r'([^!]*)!?([^@]*)@?(.*)') + source = re.compile(r'([^!]*)!?([^@]*)@?(.*)') - def __init__(self, bot, source, args): - match = Origin.source.match(source or '') - self.nick, self.user, self.host = match.groups() + def __init__(self, bot, source, args): + source = source.decode('utf-8') + match = Origin.source.match(source or '') + self.nick, self.user, self.host = match.groups() - if len(args) > 1: - target = args[1] - else: target = None + if len(args) > 1: + target = args[1] + else: target = None - mappings = {bot.nick: self.nick, None: None} - self.sender = mappings.get(target, target) + mappings = {bot.nick: self.nick, None: None} + self.sender = mappings.get(target, target) class Bot(asynchat.async_chat): - def __init__(self, nick, name, channels, password=None): - asynchat.async_chat.__init__(self) - self.set_terminator('\n') - self.buffer = '' + def __init__(self, nick, name, channels, password=None): + asynchat.async_chat.__init__(self) + self.set_terminator(b'\n') + self.buffer = b'' - self.nick = nick - self.user = nick - self.name = name - self.password = password + self.nick = nick + self.user = nick + self.name = name + self.password = password - self.verbose = True - self.channels = channels or [] - self.stack = [] + self.verbose = True + self.channels = channels or [] + self.stack = [] - import threading - self.sending = threading.RLock() + import threading + self.sending = threading.RLock() - # def push(self, *args, **kargs): - # asynchat.async_chat.push(self, *args, **kargs) + # def push(self, *args, **kargs): + # asynchat.async_chat.push(self, *args, **kargs) - def __write(self, args, text=None): - # print '%r %r %r' % (self, args, text) - try: - if text is not None: - self.push((' '.join(args) + ' :' + text)[:512] + '\r\n') - else: self.push(' '.join(args)[:512] + '\r\n') - except IndexError: - pass + def __write(self, args, text=None): + # print '%r %r %r' % (self, args, text) + try: + if text is not None: + self.push((b' '.join(args) + b' :' + text)[:512] + b'\r\n') + else: + self.push(b' '.join(args)[:512] + b'\r\n') + except IndexError: + pass - def write(self, args, text=None): - # This is a safe version of __write - def safe(input): - input = input.replace('\n', '') - input = input.replace('\r', '') - return input.encode('utf-8') - try: - args = [safe(arg) for arg in args] - if text is not None: - text = safe(text) - self.__write(args, text) - except Exception, e: pass + def write(self, args, text=None): + print(args, text) + # This is a safe version of __write + def safe(input): + input = input.replace('\n', '') + input = input.replace('\r', '') + return input.encode('utf-8') + try: + args = [safe(arg) for arg in args] + if text is not None: + text = safe(text) + self.__write(args, text) + except Exception as e: + pass - def run(self, host, port=6667, ssl=False, ipv6=False): - self.initiate_connect(host, port, ssl, ipv6) + def run(self, host, port=6667, ssl=False, ipv6=False): + self.initiate_connect(host, port, ssl, ipv6) - def initiate_connect(self, host, port, ssl, ipv6): - if self.verbose: - message = 'Connecting to %s:%s...' % (host, port) - print >> sys.stderr, message, - if ipv6 and socket.has_ipv6: - af = socket.AF_INET6 - else: - af = socket.AF_INET - self.create_socket(af, socket.SOCK_STREAM) - self.connect((host, port)) - if ssl: - import ssl - self.socket = ssl.wrap_socket(self.socket) - try: asyncore.loop() - except KeyboardInterrupt: - sys.exit() + def initiate_connect(self, host, port, use_ssl, ipv6): + if self.verbose: + message = 'Connecting to %s:%s...' % (host, port) + print(message, end=' ', file=sys.stderr) + if ipv6 and socket.has_ipv6: + af = socket.AF_INET6 + else: + af = socket.AF_INET + self.create_socket(af, socket.SOCK_STREAM, use_ssl) + self.connect((host, port)) + try: asyncore.loop() + except KeyboardInterrupt: + sys.exit() - def handle_connect(self): - if self.verbose: - print >> sys.stderr, 'connected!' - if self.password: - self.write(('PASS', self.password)) - self.write(('NICK', self.nick)) - self.write(('USER', self.user, '+iw', self.nick), self.name) + def create_socket(self, family, type, use_ssl=False): + self.family_and_type = family, type + sock = socket.socket(family, type) + if use_ssl: + sock = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLSv1) + # FIXME: ssl module does not appear to work properly with nonblocking sockets + #sock.setblocking(0) + self.set_socket(sock) - def handle_close(self): - self.close() - print >> sys.stderr, 'Closed!' + def handle_connect(self): + if self.verbose: + print('connected!', file=sys.stderr) + if self.password: + self.write(('PASS', self.password)) + self.write(('NICK', self.nick)) + self.write(('USER', self.user, '+iw', self.nick), self.name) - def collect_incoming_data(self, data): - self.buffer += data + def handle_close(self): + self.close() + print('Closed!', file=sys.stderr) - def found_terminator(self): - line = self.buffer - if line.endswith('\r'): - line = line[:-1] - self.buffer = '' + def collect_incoming_data(self, data): + self.buffer += data - # print line - if line.startswith(':'): - source, line = line[1:].split(' ', 1) - else: source = None + def found_terminator(self): + line = self.buffer + if line.endswith(b'\r'): + line = line[:-1] + self.buffer = b'' - if ' :' in line: - argstr, text = line.split(' :', 1) - else: argstr, text = line, '' - args = argstr.split() + # print line + if line.startswith(b':'): + source, line = line[1:].split(b' ', 1) + else: source = None - origin = Origin(self, source, args) - self.dispatch(origin, tuple([text] + args)) + if b' :' in line: + argstr, text = line.split(b' :', 1) + else: argstr, text = line, b'' + args = argstr.split() - if args[0] == 'PING': - self.write(('PONG', text)) + origin = Origin(self, source, args) + self.dispatch(origin, tuple([text] + args)) - def dispatch(self, origin, args): - pass + if args[0] == b'PING': + self.write(('PONG', text)) - def msg(self, recipient, text): - self.sending.acquire() + def dispatch(self, origin, args): + pass - # Cf. http://swhack.com/logs/2006-03-01#T19-43-25 - if isinstance(text, unicode): - try: text = text.encode('utf-8') - except UnicodeEncodeError, e: - text = e.__class__ + ': ' + str(e) - if isinstance(recipient, unicode): - try: recipient = recipient.encode('utf-8') - except UnicodeEncodeError, e: - return + def msg(self, recipient, text): + self.sending.acquire() - # No messages within the last 3 seconds? Go ahead! - # Otherwise, wait so it's been at least 0.8 seconds + penalty - if self.stack: - elapsed = time.time() - self.stack[-1][0] - if elapsed < 3: - penalty = float(max(0, len(text) - 50)) / 70 - wait = 0.8 + penalty - if elapsed < wait: - time.sleep(wait - elapsed) + # Cf. http://swhack.com/logs/2006-03-01#T19-43-25 + if isinstance(text, str): + try: text = text.encode('utf-8') + except UnicodeEncodeError as e: + text = e.__class__ + ': ' + str(e) + if isinstance(recipient, str): + try: recipient = recipient.encode('utf-8') + except UnicodeEncodeError as e: + return - # Loop detection - messages = [m[1] for m in self.stack[-8:]] - if messages.count(text) >= 5: - text = '...' - if messages.count('...') >= 3: - self.sending.release() - return + # No messages within the last 3 seconds? Go ahead! + # Otherwise, wait so it's been at least 0.8 seconds + penalty + if self.stack: + elapsed = time.time() - self.stack[-1][0] + if elapsed < 3: + penalty = float(max(0, len(text) - 50)) / 70 + wait = 0.8 + penalty + if elapsed < wait: + time.sleep(wait - elapsed) - def safe(input): - input = input.replace('\n', '') - return input.replace('\r', '') - self.__write(('PRIVMSG', safe(recipient)), safe(text)) - self.stack.append((time.time(), text)) - self.stack = self.stack[-10:] + # Loop detection + messages = [m[1] for m in self.stack[-8:]] + if messages.count(text) >= 5: + text = '...' + if messages.count('...') >= 3: + self.sending.release() + return - self.sending.release() + def safe(input): + input = input.replace(b'\n', b'') + return input.replace(b'\r', b'') + self.__write((b'PRIVMSG', safe(recipient)), safe(text)) + self.stack.append((time.time(), text)) + self.stack = self.stack[-10:] - def action(self, recipient, text): - text = "ACTION %s" % text - textu = chr(1) + text + chr(1) - return self.msg(recipient, textu) + self.sending.release() - def notice(self, dest, text): - self.write(('NOTICE', dest), text) + def action(self, recipient, text): + text = "ACTION %s" % text + textu = chr(1) + text + chr(1) + return self.msg(recipient, textu) - def error(self, origin): - try: - import traceback - trace = traceback.format_exc() - print trace - lines = list(reversed(trace.splitlines())) + def notice(self, dest, text): + self.write((b'NOTICE', dest), text) - report = [lines[0].strip()] - for line in lines: - line = line.strip() - if line.startswith('File "/'): - report.append(line[0].lower() + line[1:]) - break - else: report.append('source unknown') + def error(self, origin): + try: + import traceback + trace = traceback.format_exc() + print(trace) + lines = list(reversed(trace.splitlines())) + + report = [lines[0].strip()] + for line in lines: + line = line.strip() + if line.startswith('File "/'): + report.append(line[0].lower() + line[1:]) + break + else: report.append('source unknown') + + self.msg(origin.sender, report[0] + ' (' + report[1] + ')') + except: self.msg(origin.sender, "Got an error.") - self.msg(origin.sender, report[0] + ' (' + report[1] + ')') - except: self.msg(origin.sender, "Got an error.") class TestBot(Bot): - def f_ping(self, origin, match, args): - delay = m.group(1) - if delay is not None: - import time - time.sleep(int(delay)) - self.msg(origin.sender, 'pong (%s)' % delay) - else: self.msg(origin.sender, 'pong') - f_ping.rule = r'^\.ping(?:[ \t]+(\d+))?$' + def f_ping(self, origin, match, args): + delay = m.group(1) + if delay is not None: + import time + time.sleep(int(delay)) + self.msg(origin.sender, 'pong (%s)' % delay) + else: self.msg(origin.sender, 'pong') + f_ping.rule = r'^\.ping(?:[ \t]+(\d+))?$' def main(): - # bot = TestBot('testbot', ['#d8uv.com']) - # bot.run('irc.freenode.net') - print __doc__ + bot = TestBot('testbot007', 'testbot007', ['#wadsworth']) + bot.run('irc.freenode.net') + print(__doc__) if __name__=="__main__": - main() + main() diff --git a/modules/8ball.py b/modules/8ball.py index 8f43106..a289a2b 100644 --- a/modules/8ball.py +++ b/modules/8ball.py @@ -48,5 +48,5 @@ def eightball(phenny, input): eightball.commands = ['8ball'] if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/admin.py b/modules/admin.py index 249f117..e6c25e8 100755 --- a/modules/admin.py +++ b/modules/admin.py @@ -60,4 +60,4 @@ me.rule = (['me'], r'(#?\S+) (.*)') me.priority = 'low' if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/archwiki.py b/modules/archwiki.py index e954e09..69502de 100755 --- a/modules/archwiki.py +++ b/modules/archwiki.py @@ -10,7 +10,7 @@ modified from Wikipedia module author: mutantmonkey """ -import re, urllib +import re, urllib.request, urllib.parse, urllib.error import web import json @@ -65,9 +65,9 @@ def awik(phenny, input): origterm = input.groups()[1] if not origterm: return phenny.say('Perhaps you meant ".awik dwm"?') - origterm = origterm.encode('utf-8') + origterm = origterm - term = urllib.unquote(origterm) + term = urllib.parse.unquote(origterm) term = term[0].upper() + term[1:] term = term.replace(' ', '_') @@ -84,4 +84,4 @@ awik.commands = ['awik'] awik.priority = 'high' if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/botfun.py b/modules/botfun.py index 9deea49..2b25f0a 100755 --- a/modules/botfun.py +++ b/modules/botfun.py @@ -22,5 +22,5 @@ bothug.commands = ['bothug'] bothug.priority = 'low' if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/botsnack.py b/modules/botsnack.py index 93ca31a..43aaa24 100755 --- a/modules/botsnack.py +++ b/modules/botsnack.py @@ -44,12 +44,12 @@ def botsnack(phenny, input): # ignore this invocation. Else reset to the default state if botsnack.coolingdown: if now - botsnack.coolingstarted > botsnack.coolingperiod: - print "cooling down over, reseting" + print("cooling down over, reseting") botsnack.coolingdown = False botsnack.hunger = 50.0 botsnack.last_tick = now else: - print "cooling down! %s < %s" %(now - botsnack.coolingstarted, botsnack.coolingperiod) + print("cooling down! %s < %s" %(now - botsnack.coolingstarted, botsnack.coolingperiod)) return # ignore! # 1. Time has has passed, so the bot has gotten @@ -60,7 +60,7 @@ def botsnack(phenny, input): botsnack.hunger = increase_hunger(old_hunger, delta) - print "hunger was %s, increased to %s" %(old_hunger, botsnack.hunger) + print("hunger was %s, increased to %s" %(old_hunger, botsnack.hunger)) botsnack.last_tick = now @@ -68,7 +68,7 @@ def botsnack(phenny, input): old_hunger = botsnack.hunger botsnack.hunger = decrease_hunger(old_hunger, random.uniform(1,5)) - print "hunger was %s, decreased to %s" %(old_hunger, botsnack.hunger) + print("hunger was %s, decreased to %s" %(old_hunger, botsnack.hunger)) if botsnack.hunger > 95: # special case to prevent abuse phenny.say("Too much food!") @@ -106,5 +106,5 @@ botsnack.last_tick = time.time() botsnack.coolingdown = False if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/calc.py b/modules/calc.py index 9a5b187..fcea71b 100755 --- a/modules/calc.py +++ b/modules/calc.py @@ -17,8 +17,8 @@ r_tag = re.compile(r'<\S+.*?>') subs = [ (' in ', ' -> '), (' over ', ' / '), - (u'£', 'GBP '), - (u'€', 'EUR '), + ('£', 'GBP '), + ('€', 'EUR '), ('\$', 'USD '), (r'\bKB\b', 'kilobytes'), (r'\bMB\b', 'megabytes'), @@ -41,7 +41,7 @@ def calc(phenny, input): precision = 5 if query[-3:] in ('GBP', 'USD', 'EUR', 'NOK'): precision = 2 - query = web.urllib.quote(query.encode('utf-8')) + query = web.quote(query) uri = 'http://futureboy.us/fsp/frink.fsp?fromVal=' bytes = web.get(uri + query) @@ -71,18 +71,18 @@ def c(phenny, input): """Google calculator.""" if not input.group(2): return phenny.reply("Nothing to calculate.") - q = input.group(2).encode('utf-8') + q = input.group(2) q = q.replace('\xcf\x95', 'phi') # utf-8 U+03D5 q = q.replace('\xcf\x80', 'pi') # utf-8 U+03C0 uri = 'http://www.google.com/ig/calculator?q=' - bytes = web.get(uri + web.urllib.quote(q)) + bytes = web.get(uri + web.quote(q)) parts = bytes.split('",') answer = [p for p in parts if p.startswith('rhs: "')][0][6:] if answer: answer = answer.decode('unicode-escape') answer = ''.join(chr(ord(c)) for c in answer) answer = answer.decode('utf-8') - answer = answer.replace(u'\xc2\xa0', ',') + answer = answer.replace('\xc2\xa0', ',') answer = answer.replace('', '^(') answer = answer.replace('', ')') answer = web.decode(answer) @@ -92,9 +92,9 @@ c.commands = ['c'] c.example = '.c 5 + 3' def py(phenny, input): - query = input.group(2).encode('utf-8') + query = input.group(2) uri = 'http://tumbolia.appspot.com/py/' - answer = web.get(uri + web.urllib.quote(query)) + answer = web.get(uri + web.quote(query)) if answer: phenny.say(answer) else: phenny.reply('Sorry, no result.') @@ -103,13 +103,13 @@ py.commands = ['py'] def wa(phenny, input): if not input.group(2): return phenny.reply("No search term.") - query = input.group(2).encode('utf-8') + query = input.group(2) uri = 'http://tumbolia.appspot.com/wa/' - answer = web.get(uri + web.urllib.quote(query.replace('+', '%2B'))) + answer = web.get(uri + web.quote(query.replace('+', '%2B'))) if answer: phenny.say(answer) else: phenny.reply('Sorry, no result.') wa.commands = ['wa'] if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/chillmeter.py b/modules/chillmeter.py index 97657ab..4ff8e24 100644 --- a/modules/chillmeter.py +++ b/modules/chillmeter.py @@ -131,4 +131,4 @@ chill.commands = ['chill'] chill.priority = 'low' if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/clock.py b/modules/clock.py index e31c00e..7b27c0c 100755 --- a/modules/clock.py +++ b/modules/clock.py @@ -7,7 +7,7 @@ Licensed under the Eiffel Forum License 2. http://inamidst.com/phenny/ """ -import re, math, time, urllib, locale, socket, struct, datetime +import re, math, time, urllib.request, urllib.parse, urllib.error, locale, socket, struct, datetime from decimal import Decimal as dec from tools import deprecated @@ -203,9 +203,9 @@ def f_time(self, origin, match, args): People = self.config.timezones else: People = {} - if People.has_key(tz): + if tz in People: tz = People[tz] - elif (not match.group(2)) and People.has_key(origin.nick): + elif (not match.group(2)) and origin.nick in People: tz = People[origin.nick] TZ = tz.upper() @@ -218,7 +218,7 @@ def f_time(self, origin, match, args): locale.setlocale(locale.LC_TIME, (tz[1:-1], 'UTF-8')) msg = time.strftime("%A, %d %B %Y %H:%M:%SZ", time.gmtime()) self.msg(origin.sender, msg) - elif TimeZones.has_key(TZ): + elif TZ in TimeZones: offset = TimeZones[TZ] * 3600 timenow = time.gmtime(time.time() + offset) msg = time.strftime("%a, %d %b %Y %H:%M:%S " + str(TZ), timenow) @@ -273,7 +273,7 @@ yi.priority = 'low' def tock(phenny, input): """Shows the time from the USNO's atomic clock.""" - u = urllib.urlopen('http://tycho.usno.navy.mil/cgi-bin/timer.pl') + u = urllib.request.urlopen('http://tycho.usno.navy.mil/cgi-bin/timer.pl') info = u.info() u.close() phenny.say('"' + info['Date'] + '" - tycho.usno.navy.mil') @@ -290,7 +290,7 @@ def npl(phenny, input): d = dec('0.0') for i in range(8): d += dec(buf[32 + i]) * dec(str(math.pow(2, (3 - i) * 8))) - d -= dec(2208988800L) + d -= dec(2208988800) a, b = str(d).split('.') f = '%Y-%m-%d %H:%M:%S' result = datetime.datetime.fromtimestamp(d).strftime(f) + '.' + b[:6] @@ -300,4 +300,4 @@ npl.commands = ['npl'] npl.priority = 'high' if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/codepoints.py b/modules/codepoints.py index eb9c8bf..66d2ee0 100755 --- a/modules/codepoints.py +++ b/modules/codepoints.py @@ -21,7 +21,7 @@ def about(u, cp=None, name=None): if not unicodedata.combining(u): template = 'U+%04X %s (%s)' else: template = 'U+%04X %s (\xe2\x97\x8c%s)' - return template % (cp, name, u.encode('utf-8')) + return template % (cp, name, u) def codepoint_simple(arg): arg = arg.upper() @@ -29,8 +29,8 @@ def codepoint_simple(arg): r_label = re.compile('\\b' + arg.replace(' ', '.*\\b') + '\\b') results = [] - for cp in xrange(0xFFFF): - u = unichr(cp) + for cp in range(0xFFFF): + u = chr(cp) try: name = unicodedata.name(u) except ValueError: continue @@ -38,8 +38,8 @@ def codepoint_simple(arg): results.append((len(name), u, cp, name)) if not results: r_label = re.compile('\\b' + arg.replace(' ', '.*\\b')) - for cp in xrange(0xFFFF): - u = unichr(cp) + for cp in range(0xFFFF): + u = chr(cp) try: name = unicodedata.name(u) except ValueError: continue @@ -57,8 +57,8 @@ def codepoint_extended(arg): try: r_search = re.compile(arg) except: raise ValueError('Broken regexp: %r' % arg) - for cp in xrange(1, 0x10FFFF): - u = unichr(cp) + for cp in range(1, 0x10FFFF): + u = chr(cp) name = unicodedata.name(u, '-') if r_search.search(name): @@ -90,7 +90,7 @@ def u(phenny, input): break if len(arg) == 4: - try: u = unichr(int(arg, 16)) + try: u = chr(int(arg, 16)) except ValueError: pass else: return phenny.say(about(u)) @@ -131,4 +131,4 @@ bytes.commands = ['bytes'] bytes.example = '.bytes \xe3\x8b\xa1' if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/etymology.py b/modules/etymology.py index 55c5deb..e78683d 100755 --- a/modules/etymology.py +++ b/modules/etymology.py @@ -59,8 +59,7 @@ def etymology(word): sentence = m.group(0) try: - sentence = unicode(sentence, 'iso-8859-1') - sentence = sentence.encode('utf-8') + sentence = str(sentence, 'iso-8859-1') except: pass maxlength = 275 @@ -98,4 +97,4 @@ f_etymology.priority = 'high' if __name__=="__main__": import sys - print etymology(sys.argv[1]) + print(etymology(sys.argv[1])) diff --git a/modules/head.py b/modules/head.py index 3e4d3c7..b7f5346 100755 --- a/modules/head.py +++ b/modules/head.py @@ -7,20 +7,20 @@ Licensed under the Eiffel Forum License 2. http://inamidst.com/phenny/ """ -import re, urllib, urllib2, httplib, urlparse, time, cookielib -from htmlentitydefs import name2codepoint +import re, urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse, http.client, urllib.parse, time, http.cookiejar +from html.entities import name2codepoint from string import join import web from tools import deprecated -cj = cookielib.LWPCookieJar() -opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) -urllib2.install_opener(opener) +cj = http.cookiejar.LWPCookieJar() +opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj)) +urllib.request.install_opener(opener) def head(phenny, input): """Provide HTTP HEAD information.""" uri = input.group(2) - uri = (uri or '').encode('utf-8') + uri = (uri or '') if ' ' in uri: uri, header = uri.rsplit(' ', 1) else: uri, header = uri, None @@ -35,7 +35,7 @@ def head(phenny, input): try: info = web.head(uri) except IOError: return phenny.say("Can't connect to %s" % uri) - except httplib.InvalidURL: return phenny.say("Not a valid URI, sorry.") + except http.client.InvalidURL: return phenny.say("Not a valid URI, sorry.") if not isinstance(info, list): try: info = dict(info) @@ -49,20 +49,20 @@ def head(phenny, input): if header is None: data = [] - if info.has_key('Status'): + if 'Status' in info: data.append(info['Status']) - if info.has_key('content-type'): + if 'content-type' in info: data.append(info['content-type'].replace('; charset=', ', ')) - if info.has_key('last-modified'): + if 'last-modified' in info: modified = info['last-modified'] modified = time.strptime(modified, '%a, %d %b %Y %H:%M:%S %Z') data.append(time.strftime('%Y-%m-%d %H:%M:%S UTC', modified)) - if info.has_key('content-length'): + if 'content-length' in info: data.append(info['content-length'] + ' bytes') phenny.reply(', '.join(data)) else: headerlower = header.lower() - if info.has_key(headerlower): + if headerlower in info: phenny.say(header + ': ' + info.get(headerlower)) else: msg = 'There was no %s header in the response.' % header @@ -77,7 +77,7 @@ r_entity = re.compile(r'&[A-Za-z0-9#]+;') def f_title(self, origin, match, args): """.title - Return the title of URI.""" uri = match.group(2) - uri = (uri or '').encode('utf-8') + uri = (uri or '') if not uri and hasattr(self, 'last_seen_uri'): uri = self.last_seen_uri.get(origin.sender) @@ -90,7 +90,7 @@ def f_title(self, origin, match, args): f_title.commands = ['title'] def noteuri(phenny, input): - uri = input.group(1).encode('utf-8') + uri = input.group(1) if not hasattr(phenny.bot, 'last_seen_uri'): phenny.bot.last_seen_uri = {} phenny.bot.last_seen_uri[input.sender] = uri @@ -101,7 +101,7 @@ titlecommands = r'(?:' + join(f_title.commands, r'|') + r')' def snarfuri(phenny, input): if re.match(r'(?i)' + phenny.config.prefix + titlecommands, input.group()): return - uri = input.group(1).encode('utf-8') + uri = input.group(1) title = gettitle(uri) if title: phenny.msg(input.sender, '[ ' + title + ' ]') @@ -137,7 +137,7 @@ def gettitle(uri): status = str(info[1]) info = info[0] if status.startswith('3'): - uri = urlparse.urljoin(uri, info['Location']) + uri = urllib.parse.urljoin(uri, info['Location']) else: break redirects += 1 @@ -173,20 +173,20 @@ def gettitle(uri): entity = m.group(0) if entity.startswith('&#x'): cp = int(entity[3:-1], 16) - return unichr(cp).encode('utf-8') + return chr(cp) elif entity.startswith('&#'): cp = int(entity[2:-1]) - return unichr(cp).encode('utf-8') + return chr(cp) else: char = name2codepoint[entity[1:-1]] - return unichr(char).encode('utf-8') + return chr(char) title = r_entity.sub(e, title) if title: try: title.decode('utf-8') except: - try: title = title.decode('iso-8859-1').encode('utf-8') - except: title = title.decode('cp1252').encode('utf-8') + try: title = title.decode('iso-8859-1') + except: title = title.decode('cp1252') else: pass title = title.replace('\n', '') title = title.replace('\r', '') @@ -194,4 +194,4 @@ def gettitle(uri): return title if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/hs.py b/modules/hs.py index 338efab..a8f5031 100755 --- a/modules/hs.py +++ b/modules/hs.py @@ -5,7 +5,7 @@ author: mutantmonkey """ import ldap -from urllib import quote as urlquote +from urllib.parse import quote as urlquote LDAP_URI = "ldap://directory.vt.edu" RESULTS_URL = "http://search.vt.edu/search/people.html?q={0}" @@ -56,5 +56,5 @@ def hs(phenny, input): hs.rule = (['hs'], r'(.*)') if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/info.py b/modules/info.py index 73d7f88..a72c2da 100755 --- a/modules/info.py +++ b/modules/info.py @@ -12,7 +12,7 @@ def doc(phenny, input): name = input.group(1) name = name.lower() - if phenny.doc.has_key(name): + if name in phenny.doc: phenny.reply(phenny.doc[name][0]) if phenny.doc[name][1]: phenny.say('e.g. ' + phenny.doc[name][1]) @@ -23,7 +23,7 @@ doc.priority = 'low' def commands(phenny, input): # This function only works in private message if input.sender.startswith('#'): return - names = ', '.join(sorted(phenny.doc.iterkeys())) + names = ', '.join(sorted(phenny.doc.keys())) phenny.say('Commands I recognise: ' + names + '.') phenny.say(("For help, do '%s: help example?' where example is the " + "name of the command you want help for.") % phenny.nick) @@ -49,7 +49,7 @@ def stats(phenny, input): channels = {} ignore = set(['f_note', 'startup', 'message', 'noteuri']) - for (name, user), count in phenny.stats.items(): + for (name, user), count in list(phenny.stats.items()): if name in ignore: continue if not user: continue @@ -63,9 +63,9 @@ def stats(phenny, input): try: channels[user] += count except KeyError: channels[user] = count - comrank = sorted([(b, a) for (a, b) in commands.iteritems()], reverse=True) - userank = sorted([(b, a) for (a, b) in users.iteritems()], reverse=True) - charank = sorted([(b, a) for (a, b) in channels.iteritems()], reverse=True) + comrank = sorted([(b, a) for (a, b) in commands.items()], reverse=True) + userank = sorted([(b, a) for (a, b) in users.items()], reverse=True) + charank = sorted([(b, a) for (a, b) in channels.items()], reverse=True) # most heavily used commands creply = 'most used commands: ' @@ -88,4 +88,4 @@ stats.commands = ['stats'] stats.priority = 'low' if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/lastfm.py b/modules/lastfm.py index b43c416..d4a34d8 100644 --- a/modules/lastfm.py +++ b/modules/lastfm.py @@ -7,9 +7,10 @@ author: Casey Link import random -import ConfigParser, os -from urllib import quote as urlquote -from urllib2 import urlopen, HTTPError +import configparser, os +from urllib.parse import quote as urlquote +from urllib.request import urlopen +from urllib.error import HTTPError from lxml import etree from datetime import datetime @@ -17,7 +18,7 @@ APIKEY = "b25b959554ed76058ac220b7b2e0a026" APIURL = "http://ws.audioscrobbler.com/2.0/?api_key="+APIKEY+"&" AEPURL = "http://www.davethemoonman.com/lastfm/aep.php?format=txt&username=" -config = ConfigParser.RawConfigParser() +config = configparser.RawConfigParser() config.optionxform = str config_filename = "" @@ -84,7 +85,7 @@ def now_playing(phenny, input): user = user.strip() try: req = urlopen("%smethod=user.getrecenttracks&user=%s" % (APIURL, urlquote(user))) - except HTTPError, e: + except HTTPError as e: if e.code == 400: phenny.say("%s doesn't exist on last.fm, perhaps they need to set user" % (user)) return @@ -151,7 +152,7 @@ def aep(phenny, input): user = user.strip() try: req = urlopen("%s%s" % (AEPURL, urlquote(user))) - except HTTPError, e: + except HTTPError as e: phenny.say("uhoh. try again later, mmkay?") return result = req.read() @@ -182,7 +183,7 @@ def tasteometer(phenny, input): user2 = input.nick try: req = urlopen("%smethod=tasteometer.compare&type1=user&type2=user&value1=%s&value2=%s" % (APIURL, urlquote(user1), urlquote(user2))) - except HTTPError, e: + except HTTPError as e: if e.code == 400: phenny.say("uhoh, someone doesn't exist on last.fm, perhaps they need to set user") return @@ -217,7 +218,7 @@ def tasteometer(phenny, input): if len(artists) == 0: common_artists = ". they don't have any artists in common." else: - map(lambda a: names.append(a.text) ,artists) + list(map(lambda a: names.append(a.text) ,artists)) common_artists = "and music they have in common includes: %s" % ", ".join(names) phenny.say("%s's and %s's musical compatibility rating is %s %s" % (user1, user2, rating, common_artists)) @@ -294,4 +295,4 @@ def pretty_date(time=False): return str(day_diff/365) + " years ago" if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/mylife.py b/modules/mylife.py index 871d6e6..90a275e 100644 --- a/modules/mylife.py +++ b/modules/mylife.py @@ -7,8 +7,7 @@ author: mutantmonkey import random -from urllib import quote as urlquote -from urllib2 import HTTPError +from urllib.error import HTTPError import web import lxml.html @@ -16,7 +15,7 @@ def fml(phenny, input): """.fml""" try: req = web.get("http://www.fmylife.com/random") - except HTTPError, IOError: + except (HTTPError, IOError): phenny.say("I tried to use .fml, but it was broken. FML") return @@ -29,7 +28,7 @@ def mlia(phenny, input): """.mlia - My life is average.""" try: req = web.get("http://mylifeisaverage.com/") - except HTTPError, IOError: + except (HTTPError, IOError): phenny.say("I tried to use .mlia, but it wasn't loading. MLIA") return @@ -43,7 +42,7 @@ def mliarab(phenny, input): """.mliarab - My life is Arabic.""" try: req = web.get("http://mylifeisarabic.com/random/") - except HTTPError, IOError: + except (HTTPError, IOError): phenny.say("The site you requested, mylifeisarabic.com, has been banned \ in the UAE. You will be reported to appropriate authorities") return @@ -59,7 +58,7 @@ def mlib(phenny, input): """.mlib - My life is bro.""" try: req = web.get("http://mylifeisbro.com/random") - except HTTPError, IOError: + except (HTTPError, IOError): phenny.say("MLIB is out getting a case of Natty. It's chill.") return @@ -72,7 +71,7 @@ def mlic(phenny, input): """.mlic - My life is creepy.""" try: req = web.get("http://mylifeiscreepy.com/random") - except HTTPError, IOError: + except (HTTPError, IOError): phenny.say("Error: Have you checked behind you?") return @@ -86,7 +85,7 @@ def mlid(phenny, input): """.mlib - My life is Desi.""" try: req = web.get("http://www.mylifeisdesi.com/random") - except HTTPError, IOError: + except (HTTPError, IOError): phenny.say("MLID is busy at the hookah lounge, be back soon.") return @@ -99,7 +98,7 @@ def mlig(phenny, input): """.mlig - My life is ginger.""" try: req = web.get("http://www.mylifeisginger.org/random") - except HTTPError, IOError: + except (HTTPError, IOError): phenny.say("Busy eating your soul. Be back soon.") return @@ -112,7 +111,7 @@ def mlih(phenny, input): """.mlih - My life is ho.""" try: req = web.get("http://mylifeisho.com/random") - except HTTPError, IOError: + except (HTTPError, IOError): phenny.say("MLIH is giving some dome to some lax bros.") return @@ -125,7 +124,7 @@ def mlihp(phenny, input): """.mlihp - My life is Harry Potter.""" try: req = web.get("http://www.mylifeishp.com/random") - except HTTPError, IOError: + except (HTTPError, IOError): phenny.say("This service is not available to Muggles.") return @@ -138,7 +137,7 @@ def mlit(phenny, input): """.mlit - My life is Twilight.""" try: req = web.get("http://mylifeistwilight.com/random") - except HTTPError, IOError: + except (HTTPError, IOError): phenny.say("Error: Your life is too Twilight. Go outside.") return @@ -148,5 +147,5 @@ def mlit(phenny, input): mlit.commands = ['mlit'] if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/nsfw.py b/modules/nsfw.py index d30aa8c..abc5d87 100755 --- a/modules/nsfw.py +++ b/modules/nsfw.py @@ -14,5 +14,5 @@ def nsfw(phenny, input): nsfw.rule = (['nsfw'], r'(.*)') if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/oblique.py b/modules/oblique.py index 7bd6718..3409a4d 100755 --- a/modules/oblique.py +++ b/modules/oblique.py @@ -7,7 +7,7 @@ Licensed under the Eiffel Forum License 2. http://inamidst.com/phenny/ """ -import re, urllib +import re, urllib.request, urllib.parse, urllib.error import web definitions = 'https://github.com/nslater/oblique/wiki' @@ -30,9 +30,9 @@ def mappings(uri): def service(phenny, input, command, args): t = o.services[command] - template = t.replace('${args}', urllib.quote(args.encode('utf-8'), '')) - template = template.replace('${nick}', urllib.quote(input.nick, '')) - uri = template.replace('${sender}', urllib.quote(input.sender, '')) + template = t.replace('${args}', urllib.parse.quote(args, '')) + template = template.replace('${nick}', urllib.parse.quote(input.nick, '')) + uri = template.replace('${sender}', urllib.parse.quote(input.sender, '')) info = web.head(uri) if isinstance(info, list): @@ -80,7 +80,7 @@ def o(phenny, input): msg = o.services.get(args, 'No such service!') return phenny.reply(msg) - if not o.services.has_key(command): + if command not in o.services: return phenny.reply('Service not found in %s' % o.serviceURI) if hasattr(phenny.config, 'external'): @@ -102,7 +102,7 @@ def snippet(phenny, input): if not o.services: refresh(phenny) - search = urllib.quote(input.group(2).encode('utf-8')) + search = urllib.parse.quote(input.group(2)) py = "BeautifulSoup.BeautifulSoup(re.sub('<.*?>|(?<= ) +', '', " + \ "''.join(chr(ord(c)) for c in " + \ "eval(urllib.urlopen('http://ajax.googleapis.com/ajax/serv" + \ @@ -114,4 +114,4 @@ def snippet(phenny, input): snippet.commands = ['snippet'] if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/ping.py b/modules/ping.py index 23219ac..3e963a0 100755 --- a/modules/ping.py +++ b/modules/ping.py @@ -20,4 +20,4 @@ interjection.priority = 'high' interjection.thread = False if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/reload.py b/modules/reload.py index dfd0e8e..e270863 100755 --- a/modules/reload.py +++ b/modules/reload.py @@ -24,7 +24,7 @@ def f_reload(phenny, input): phenny.setup() return phenny.reply('done') - if not sys.modules.has_key(name): + if name not in sys.modules: return phenny.reply('%s: no such module!' % name) # Thanks to moot for prodding me on this @@ -52,4 +52,4 @@ f_reload.priority = 'low' f_reload.thread = False if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/remind.py b/modules/remind.py index ec1a4d1..36152be 100755 --- a/modules/remind.py +++ b/modules/remind.py @@ -16,7 +16,7 @@ def filename(self): def load_database(name): data = {} if os.path.isfile(name): - f = open(name, 'rb') + f = open(name, 'r') for line in f: unixtime, channel, nick, message = line.split('\t') message = message.rstrip('\n') @@ -28,8 +28,8 @@ def load_database(name): return data def dump_database(name, data): - f = open(name, 'wb') - for unixtime, reminders in data.iteritems(): + f = open(name, 'w') + for unixtime, reminders in data.items(): for channel, nick, message in reminders: f.write('%s\t%s\t%s\t%s\n' % (unixtime, channel, nick, message)) f.close() @@ -97,12 +97,12 @@ scaling = { 's': 1 } -periods = '|'.join(scaling.keys()) +periods = '|'.join(list(scaling.keys())) p_command = r'\.in ([0-9]+(?:\.[0-9]+)?)\s?((?:%s)\b)?:?\s?(.*)' % periods r_command = re.compile(p_command) def remind(phenny, input): - m = r_command.match(input.bytes) + m = r_command.match(input.bytes.decode('utf-8')) if not m: return phenny.reply("Sorry, didn't understand the input.") length, scale, message = m.groups() @@ -133,4 +133,4 @@ def remind(phenny, input): remind.commands = ['in'] if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/search.py b/modules/search.py index bfc50bd..6106199 100755 --- a/modules/search.py +++ b/modules/search.py @@ -33,14 +33,14 @@ def google_search(query): try: return results['responseData']['results'][0]['unescapedUrl'] except IndexError: return None except TypeError: - print results + print(results) return False def google_count(query): results = google_ajax(query) - if not results.has_key('responseData'): return '0' - if not results['responseData'].has_key('cursor'): return '0' - if not results['responseData']['cursor'].has_key('estimatedResultCount'): + if 'responseData' not in results: return '0' + if 'cursor' not in results['responseData']: return '0' + if 'estimatedResultCount' not in results['responseData']['cursor']: return '0' return results['responseData']['cursor']['estimatedResultCount'] @@ -56,7 +56,6 @@ def g(phenny, input): query = input.group(2) if not query: return phenny.reply('.g what?') - query = query.encode('utf-8') uri = google_search(query) if uri: phenny.reply(uri) @@ -74,7 +73,6 @@ def gc(phenny, input): query = input.group(2) if not query: return phenny.reply('.gc what?') - query = query.encode('utf-8') num = formatnumber(google_count(query)) phenny.say(query + ': ' + num) gc.commands = ['gc'] @@ -95,7 +93,6 @@ def gcs(phenny, input): results = [] for i, query in enumerate(queries): query = query.strip('[]') - query = query.encode('utf-8') n = int((formatnumber(google_count(query)) or '0').replace(',', '')) results.append((n, query)) if i >= 2: __import__('time').sleep(0.25) @@ -125,7 +122,6 @@ def bing(phenny, input): if not query: return phenny.reply('.bing what?') - query = query.encode('utf-8') uri = bing_search(query, lang) if uri: phenny.reply(uri) @@ -150,7 +146,6 @@ def duck(phenny, input): query = input.group(2) if not query: return phenny.reply('.ddg what?') - query = query.encode('utf-8') uri = duck_search(query) if uri: phenny.reply(uri) @@ -163,7 +158,7 @@ duck.commands = ['duck', 'ddg'] def search(phenny, input): if not input.group(2): return phenny.reply('.search for what?') - query = input.group(2).encode('utf-8') + query = input.group(2) gu = google_search(query) or '-' bu = bing_search(query) or '-' du = duck_search(query) or '-' @@ -188,7 +183,7 @@ search.commands = ['search'] def suggest(phenny, input): if not input.group(2): return phenny.reply("No query term.") - query = input.group(2).encode('utf-8') + query = input.group(2) uri = 'http://websitedev.de/temp-bin/suggest.pl?q=' answer = web.get(uri + web.urllib.quote(query).replace('+', '%2B')) if answer: @@ -197,4 +192,4 @@ def suggest(phenny, input): suggest.commands = ['suggest'] if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/seen.py b/modules/seen.py index 26dc05f..34d8551 100755 --- a/modules/seen.py +++ b/modules/seen.py @@ -17,7 +17,7 @@ def f_seen(self, origin, match, args): nick = match.group(2).lower() if not hasattr(self, 'seen'): return self.msg(origin.sender, '?') - if self.seen.has_key(nick): + if nick in self.seen: channel, t = self.seen[nick] t = time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime(t)) @@ -41,9 +41,9 @@ def f_note(self, origin, match, args): # self.chanspeak[args[2]] = args[0] try: note(self, origin, match, args) - except Exception, e: print e + except Exception as e: print(e) f_note.rule = r'(.*)' f_note.priority = 'low' if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/slogan.py b/modules/slogan.py index 6f4bcd4..469f1ce 100755 --- a/modules/slogan.py +++ b/modules/slogan.py @@ -12,7 +12,7 @@ import web uri = 'http://www.sloganizer.net/en/outbound.php?slogan=%s' def sloganize(word): - bytes = web.get(uri % web.urllib.quote(word.encode('utf-8'))) + bytes = web.get(uri % web.quote(word)) return bytes def slogan(phenny, input): @@ -37,4 +37,4 @@ slogan.commands = ['slogan'] slogan.example = '.slogan Granola' if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/startup.py b/modules/startup.py index 6fc7fae..d69c3a1 100755 --- a/modules/startup.py +++ b/modules/startup.py @@ -23,4 +23,4 @@ startup.event = '251' startup.priority = 'low' if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/tell.py b/modules/tell.py index 8ec3912..0b6c60b 100755 --- a/modules/tell.py +++ b/modules/tell.py @@ -37,7 +37,7 @@ def loadReminders(fn): def dumpReminders(fn, data): f = open(fn, 'w') - for tellee in data.iterkeys(): + for tellee in data.keys(): for remindon in data[tellee]: line = '\t'.join((tellee,) + remindon) try: f.write(line + '\n') @@ -62,9 +62,9 @@ def f_remind(phenny, input): # @@ Multiple comma-separated tellees? Cf. Terje, #swhack, 2006-04-15 verb, tellee, msg = input.groups() - verb = verb.encode('utf-8') - tellee = tellee.encode('utf-8') - msg = msg.encode('utf-8') + verb = verb + tellee = tellee + msg = msg tellee_original = tellee.rstrip('.,:;') tellee = tellee_original.lower() @@ -79,7 +79,7 @@ def f_remind(phenny, input): if not tellee in (teller.lower(), phenny.nick, 'me'): # @@ # @@ and year, if necessary warn = False - if not phenny.reminders.has_key(tellee): + if tellee not in phenny.reminders: phenny.reminders[tellee] = [(teller, verb, timenow, msg)] else: # if len(phenny.reminders[tellee]) >= maximum: @@ -144,14 +144,14 @@ def message(phenny, input): for line in reminders[maximum:]: phenny.msg(tellee, line) - if len(phenny.reminders.keys()) != remkeys: + if len(list(phenny.reminders.keys())) != remkeys: dumpReminders(phenny.tell_filename, phenny.reminders) # @@ tell message.rule = r'(.*)' message.priority = 'low' message.thread = False def messageAlert(phenny, input): - if (input.nick.lower() in phenny.reminders.keys()): + if (input.nick.lower() in list(phenny.reminders.keys())): phenny.say(input.nick + ': You have messages.') messageAlert.event = 'JOIN' messageAlert.rule = r'.*' @@ -159,4 +159,4 @@ messageAlert.priority = 'low' messageAlert.thread = False if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/tfw.py b/modules/tfw.py index fec6584..870d683 100755 --- a/modules/tfw.py +++ b/modules/tfw.py @@ -4,8 +4,8 @@ tfw.py - the fucking weather module author: mutantmonkey """ -from urllib import quote as urlquote -from urllib2 import HTTPError +from urllib.parse import quote as urlquote +from urllib.error import HTTPError import web import lxml.html @@ -24,7 +24,7 @@ def tfw(phenny, input, fahrenheit=False, celsius=False): try: req = web.get("http://thefuckingweather.com/?zipcode=%s%s" % (urlquote(zipcode), celsius_param)) - except HTTPError: + except (HTTPError, IOError): phenny.say("THE INTERNET IS FUCKING BROKEN. Please try again later.") return @@ -46,7 +46,7 @@ def tfw(phenny, input, fahrenheit=False, celsius=False): if c.isdigit(): tempt += c temp = int(tempt) - deg = unichr(176).encode('latin-1') + deg = chr(176) # add units and convert if necessary if fahrenheit: @@ -82,5 +82,5 @@ def tfwc(phenny, input): tfwc.rule = (['tfwc'], r'(.*)') if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/translate.py b/modules/translate.py index d5ae41f..a4716ae 100755 --- a/modules/translate.py +++ b/modules/translate.py @@ -8,12 +8,12 @@ Licensed under the Eiffel Forum License 2. http://inamidst.com/phenny/ """ -import re, urllib +import re, urllib.request, urllib.parse, urllib.error import web def detect(text): uri = 'http://ajax.googleapis.com/ajax/services/language/detect' - q = urllib.quote(text) + q = urllib.parse.quote(text) bytes = web.get(uri + '?q=' + q + '&v=1.0') result = web.json(bytes) try: return result['responseData']['language'] @@ -21,7 +21,7 @@ def detect(text): def translate(text, input, output): uri = 'http://ajax.googleapis.com/ajax/services/language/translate' - q = urllib.quote(text) + q = urllib.parse.quote(text) pair = input + '%7C' + output bytes = web.get(uri + '?q=' + q + '&v=1.0&langpair=' + pair) result = web.json(bytes) @@ -32,7 +32,7 @@ def tr(phenny, context): """Translates a phrase, with an optional language hint.""" input, output, phrase = context.groups() - phrase = phrase.encode('utf-8') + phrase = phrase if (len(phrase) > 350) and (not context.admin): return phenny.reply('Phrase must be under 350 characters.') @@ -41,8 +41,7 @@ def tr(phenny, context): if not input: err = 'Unable to guess your crazy moon language, sorry.' return phenny.reply(err) - input = input.encode('utf-8') - output = (output or 'en').encode('utf-8') + output = (output or 'en') if input != output: msg = translate(phrase, input, output) @@ -56,12 +55,12 @@ def tr(phenny, context): phenny.reply(msg) else: phenny.reply('Language guessing failed, so try suggesting one!') -tr.rule = ('$nick', ur'(?:([a-z]{2}) +)?(?:([a-z]{2}) +)?["“](.+?)["”]\? *$') +tr.rule = ('$nick', r'(?:([a-z]{2}) +)?(?:([a-z]{2}) +)?["“](.+?)["”]\? *$') tr.example = '$nickname: "mon chien"? or $nickname: fr "mon chien"?' tr.priority = 'low' def mangle(phenny, input): - phrase = input.group(2).encode('utf-8') + phrase = input.group(2) for lang in ['fr', 'de', 'es', 'it', 'ja']: backup = phrase phrase = translate(phrase, 'en', lang) @@ -81,4 +80,4 @@ def mangle(phenny, input): mangle.commands = ['mangle'] if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/uncyclopedia.py b/modules/uncyclopedia.py index 4fa3102..32a0fdb 100755 --- a/modules/uncyclopedia.py +++ b/modules/uncyclopedia.py @@ -10,7 +10,7 @@ modified from Wikipedia module author: mutantmonkey """ -import re, urllib +import re, urllib.request, urllib.parse, urllib.error import web wikiuri = 'http://uncyclopedia.wikia.com/wiki/%s' @@ -46,14 +46,13 @@ def text(html): return unescape(html).strip() def search(term): - try: import search - except ImportError, e: - print e + try: from . import search + except ImportError as e: + print(e) return term - if isinstance(term, unicode): - term = term.encode('utf-8') - else: term = term.decode('utf-8') + if not isinstance(term, str): + term = term.decode('utf-8') term = term.replace('_', ' ') try: uri = search.result('site:uncyclopedia.wikia.com %s' % term) @@ -65,10 +64,10 @@ def search(term): def uncyclopedia(term, last=False): global wikiuri if not '%' in term: - if isinstance(term, unicode): - t = term.encode('utf-8') + if isinstance(term, str): + t = term else: t = term - q = urllib.quote(t) + q = urllib.parse.quote(t) u = wikiuri % q bytes = web.get(u) else: bytes = web.get(wikiuri % term) @@ -77,7 +76,7 @@ def uncyclopedia(term, last=False): if not last: r = r_redirect.search(bytes[:4096]) if r: - term = urllib.unquote(r.group(1)) + term = urllib.parse.unquote(r.group(1)) return uncyclopedia(term, last=True) paragraphs = r_paragraph.findall(bytes) @@ -138,18 +137,15 @@ def uncyclopedia(term, last=False): return None sentence = '"' + sentence.replace('"', "'") + '"' - sentence = sentence.decode('utf-8').encode('utf-8') - wikiuri = wikiuri.decode('utf-8').encode('utf-8') - term = term.decode('utf-8').encode('utf-8') return sentence + ' - ' + (wikiuri % term) def uncyc(phenny, input): origterm = input.groups()[1] if not origterm: return phenny.say('Perhaps you meant ".uncyc Zen"?') - origterm = origterm.encode('utf-8') + origterm = origterm - term = urllib.unquote(origterm) + term = urllib.parse.unquote(origterm) term = term[0].upper() + term[1:] term = term.replace(' ', '_') @@ -166,4 +162,4 @@ uncyc.commands = ['uncyc'] uncyc.priority = 'high' if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/validate.py b/modules/validate.py index 85815d1..3b2fef3 100755 --- a/modules/validate.py +++ b/modules/validate.py @@ -25,10 +25,10 @@ def val(phenny, input): if isinstance(info, list): return phenny.say('Got HTTP response %s' % info[1]) - if info.has_key('X-W3C-Validator-Status'): + if 'X-W3C-Validator-Status' in info: result += str(info['X-W3C-Validator-Status']) if info['X-W3C-Validator-Status'] != 'Valid': - if info.has_key('X-W3C-Validator-Errors'): + if 'X-W3C-Validator-Errors' in info: n = int(info['X-W3C-Validator-Errors'].split(' ')[0]) if n != 1: result += ' (%s errors)' % n @@ -40,4 +40,4 @@ val.rule = (['val'], r'(?i)(\S+)') val.example = '.val http://www.w3.org/' if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/vtluugwiki.py b/modules/vtluugwiki.py index f739d2b..27efd14 100755 --- a/modules/vtluugwiki.py +++ b/modules/vtluugwiki.py @@ -10,7 +10,7 @@ modified from Wikipedia module author: mutantmonkey """ -import re, urllib +import re, urllib.request, urllib.parse, urllib.error import web import json @@ -64,9 +64,9 @@ def vtluug(phenny, input): origterm = input.groups()[1] if not origterm: return phenny.say('Perhaps you meant ".vtluug Zen"?') - origterm = origterm.encode('utf-8') + origterm = origterm - term = urllib.unquote(origterm) + term = urllib.parse.unquote(origterm) term = term[0].upper() + term[1:] term = term.replace(' ', '_') @@ -83,4 +83,4 @@ vtluug.commands = ['vtluug'] vtluug.priority = 'high' if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/wargame.py b/modules/wargame.py index 5577d54..8296b97 100644 --- a/modules/wargame.py +++ b/modules/wargame.py @@ -8,9 +8,10 @@ author: Casey Link import random -import ConfigParser, os -from urllib import quote as urlquote -from urllib2 import urlopen, HTTPError +import configparser, os +from urllib.parse import quote as urlquote +from urllib.request import urlopen +from urllib.error import HTTPError from lxml import etree from lxml import objectify from datetime import datetime @@ -25,7 +26,7 @@ class server(object): self.players = [] def __str__(self): s = "%s - %d players: " %(self.name, len(self.players)) - s += ", ".join(map(lambda p: str(p), self.players)) + s += ", ".join([str(p) for p in self.players]) return s class player(object): @@ -79,7 +80,7 @@ def wargame(phenny, input): return try: req = urlopen(APIURL) - except HTTPError, e: + except HTTPError as e: phenny.say("uhoh. try again later, mmkay?") return root = objectify.parse(req).getroot() @@ -90,11 +91,11 @@ def wargame(phenny, input): for server_e in root.servers.server: servers.append( parse_server( server_e ) ) - phenny.say( "wargame network is %s. last updated %s. available targets: %s" % ( "ONLINE" if online else "OFFLINE", updated, ", ".join(map(lambda s: s.name, servers))) ) + phenny.say( "wargame network is %s. last updated %s. available targets: %s" % ( "ONLINE" if online else "OFFLINE", updated, ", ".join([s.name for s in servers])) ) def wargame_scores(phenny, s_name): try: req = urlopen(APIURL) - except HTTPError, e: + except HTTPError as e: phenny.say("uhoh. try again later, mmkay?") return root = objectify.parse(req).getroot() diff --git a/modules/weather.py b/modules/weather.py index 0cdea32..1f0c908 100755 --- a/modules/weather.py +++ b/modules/weather.py @@ -7,16 +7,16 @@ Licensed under the Eiffel Forum License 2. http://inamidst.com/phenny/ """ -import re, urllib +import re, urllib.request, urllib.parse, urllib.error import web from tools import deprecated r_from = re.compile(r'(?i)([+-]\d+):00 from') def location(name): - name = urllib.quote(name.encode('utf-8')) + name = urllib.parse.quote(name) uri = 'http://ws.geonames.org/searchJSON?q=%s&maxRows=1' % name - for i in xrange(10): + for i in range(10): bytes = web.get(uri) if bytes is not None: break @@ -220,25 +220,25 @@ def f_weather(self, origin, match, args): description = 'Violent storm' else: description = 'Hurricane' - degrees = wind[0:3] + degrees = float(wind[0:3] if degrees == 'VRB': - degrees = u'\u21BB'.encode('utf-8') + degrees = '\u21BB' elif (degrees <= 22.5) or (degrees > 337.5): - degrees = u'\u2191'.encode('utf-8') + degrees = '\u2191' elif (degrees > 22.5) and (degrees <= 67.5): - degrees = u'\u2197'.encode('utf-8') + degrees = '\u2197' elif (degrees > 67.5) and (degrees <= 112.5): - degrees = u'\u2192'.encode('utf-8') + degrees = '\u2192' elif (degrees > 112.5) and (degrees <= 157.5): - degrees = u'\u2198'.encode('utf-8') + degrees = '\u2198' elif (degrees > 157.5) and (degrees <= 202.5): - degrees = u'\u2193'.encode('utf-8') + degrees = '\u2193' elif (degrees > 202.5) and (degrees <= 247.5): - degrees = u'\u2199'.encode('utf-8') + degrees = '\u2199' elif (degrees > 247.5) and (degrees <= 292.5): - degrees = u'\u2190'.encode('utf-8') + degrees = '\u2190' elif (degrees > 292.5) and (degrees <= 337.5): - degrees = u'\u2196'.encode('utf-8') + degrees = '\u2196' if not icao_code.startswith('EN') and not icao_code.startswith('ED'): wind = '%s %skt (%s)' % (description, speed, degrees) @@ -274,13 +274,13 @@ def f_weather(self, origin, match, args): level = 0 if level == 8: - cover = u'Overcast \u2601'.encode('utf-8') + cover = 'Overcast \u2601' elif level == 5: cover = 'Cloudy' elif level == 3: cover = 'Scattered' elif (level == 1) or (level == 0): - cover = u'Clear \u263C'.encode('utf-8') + cover = 'Clear \u263C' else: cover = 'Cover Unknown' else: cover = 'Cover Unknown' @@ -310,10 +310,10 @@ def f_weather(self, origin, match, args): if isinstance(temp, int): f = round((temp * 1.8) + 32, 2) - temp = u'%s\u2109 (%s\u2103)'.encode('utf-8') % (f, temp) + temp = '%s\u2109 (%s\u2103)' % (f, temp) else: pressure = '?mb' if isinstance(temp, int): - temp = u'%s\u2103'.encode('utf-8') % temp + temp = '%s\u2103' % temp if cond: conds = cond @@ -397,14 +397,14 @@ def f_weather(self, origin, match, args): # args = (icao, time, cover, temp, pressure, cond, wind) if not cond: - format = u'%s, %s, %s, %s - %s %s' + format = '%s, %s, %s, %s - %s %s' args = (cover, temp, pressure, wind, str(icao_code), time) else: - format = u'%s, %s, %s, %s, %s - %s, %s' + format = '%s, %s, %s, %s, %s - %s, %s' args = (cover, temp, pressure, cond, wind, str(icao_code), time) - self.msg(origin.sender, format.encode('utf-8') % args) + self.msg(origin.sender, format % args) f_weather.rule = (['weather'], r'(.*)') if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/wikipedia.py b/modules/wikipedia.py index 1580534..8b2d29d 100755 --- a/modules/wikipedia.py +++ b/modules/wikipedia.py @@ -7,7 +7,7 @@ Licensed under the Eiffel Forum License 2. http://inamidst.com/phenny/ """ -import re, urllib, gzip, StringIO +import re, urllib.request, urllib.parse, urllib.error, gzip, io import web import json @@ -61,9 +61,9 @@ def wik(phenny, input): origterm = input.groups()[1] if not origterm: return phenny.say('Perhaps you meant ".wik Zen"?') - origterm = origterm.encode('utf-8') + origterm = origterm - term = urllib.unquote(origterm) + term = urllib.parse.unquote(origterm) term = term[0].upper() + term[1:] term = term.replace(' ', '_') @@ -80,4 +80,4 @@ wik.commands = ['wik'] wik.priority = 'high' if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/modules/wiktionary.py b/modules/wiktionary.py index 9229194..21329be 100755 --- a/modules/wiktionary.py +++ b/modules/wiktionary.py @@ -23,7 +23,7 @@ def text(html): return text def wiktionary(word): - bytes = web.get(uri % web.urllib.quote(word.encode('utf-8'))) + bytes = web.get(uri % web.urllib.quote(word)) bytes = r_ul.sub('', bytes) mode = None @@ -62,11 +62,11 @@ parts = ('preposition', 'particle', 'noun', 'verb', 'adjective', 'adverb', 'interjection') def format(word, definitions, number=2): - result = '%s' % word.encode('utf-8') + result = '%s' % word for part in parts: - if definitions.has_key(part): + if part in definitions: defs = definitions[part][:number] - result += u' \u2014 '.encode('utf-8') + ('%s: ' % part) + result += ' \u2014 ' + ('%s: ' % part) n = ['%s. %s' % (i + 1, e.strip(' .')) for i, e in enumerate(defs)] result += ', '.join(n) return result.strip(' .,') @@ -97,4 +97,4 @@ def encarta(phenny, input): encarta.commands = ['dict'] if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/opt/freenode.py b/opt/freenode.py index 0c08cf2..e7aa130 100755 --- a/opt/freenode.py +++ b/opt/freenode.py @@ -35,4 +35,4 @@ replaced.commands = [ replaced.priority = 'low' if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/phenny b/phenny index 32d3253..9a8857b 100755 --- a/phenny +++ b/phenny @@ -19,12 +19,12 @@ dotdir = os.path.expanduser('~/.phenny') def check_python_version(): if sys.version_info < (2, 4): error = 'Error: Requires Python 2.4 or later, from www.python.org' - print >> sys.stderr, error + print(error, file=sys.stderr) sys.exit(1) def create_default_config(fn): f = open(fn, 'w') - print >> f, trim("""\ + print(trim("""\ nick = 'phenny' host = 'irc.example.net' port = 6667 @@ -61,23 +61,23 @@ def create_default_config(fn): } # EOF - """) + """), file=f) f.close() def create_dotdir(dotdir): - print 'Creating a config directory at ~/.phenny...' + print('Creating a config directory at ~/.phenny...') try: os.mkdir(dotdir) - except Exception, e: - print >> sys.stderr, 'There was a problem creating %s:' % dotdir - print >> sys.stderr, e.__class__, str(e) - print >> sys.stderr, 'Please fix this and then run phenny again.' + except Exception as e: + print('There was a problem creating %s:' % dotdir, file=sys.stderr) + print(e.__class__, str(e), file=sys.stderr) + print('Please fix this and then run phenny again.', file=sys.stderr) sys.exit(1) - print 'Creating a default config file at ~/.phenny/default.py...' + print('Creating a default config file at ~/.phenny/default.py...') default = os.path.join(dotdir, 'default.py') create_default_config(default) - print 'Done; now you can edit default.py, and run phenny! Enjoy.' + print('Done; now you can edit default.py, and run phenny! Enjoy.') sys.exit(0) def check_dotdir(): @@ -107,8 +107,8 @@ def config_names(config): if os.path.isdir(there): return files(there) - print >> sys.stderr, "Error: Couldn't find a config file!" - print >> sys.stderr, 'What happened to ~/.phenny/default.py?' + print("Error: Couldn't find a config file!", file=sys.stderr) + print('What happened to ~/.phenny/default.py?', file=sys.stderr) sys.exit(1) def main(argv=None): @@ -118,7 +118,7 @@ def main(argv=None): parser.add_option('-c', '--config', metavar='fn', help='use this configuration file or directory') opts, args = parser.parse_args(argv) - if args: print >> sys.stderr, 'Warning: ignoring spurious arguments' + if args: print('Warning: ignoring spurious arguments', file=sys.stderr) # Step Two: Check Dependencies @@ -154,7 +154,7 @@ def main(argv=None): if module.host == 'irc.example.net': error = ('Error: you must edit the config file first!\n' + "You're currently using %s" % module.filename) - print >> sys.stderr, error + print(error, file=sys.stderr) sys.exit(1) config_modules.append(module) @@ -165,7 +165,7 @@ def main(argv=None): except ImportError: try: from phenny import run except ImportError: - print >> sys.stderr, "Error: Couldn't find phenny to import" + print("Error: Couldn't find phenny to import", file=sys.stderr) sys.exit(1) # Step Five: Initialise And Run The Phennies diff --git a/tools.py b/tools.py index 47d582a..78bd5f9 100755 --- a/tools.py +++ b/tools.py @@ -23,4 +23,4 @@ def deprecated(old): return new if __name__ == '__main__': - print __doc__.strip() + print(__doc__.strip()) diff --git a/web.py b/web.py index 67a4843..8017ac7 100755 --- a/web.py +++ b/web.py @@ -5,67 +5,68 @@ Author: Sean B. Palmer, inamidst.com About: http://inamidst.com/phenny/ """ -import re, urllib -from htmlentitydefs import name2codepoint +import re, urllib.request, urllib.parse, urllib.error +from html.entities import name2codepoint +import json as jsonlib -class Grab(urllib.URLopener): - def __init__(self, *args): - self.version = 'Mozilla/5.0 (Phenny)' - urllib.URLopener.__init__(self, *args) - def http_error_default(self, url, fp, errcode, errmsg, headers): - return urllib.addinfourl(fp, [headers, errcode], "http:" + url) -urllib._urlopener = Grab() +class Grab(urllib.request.URLopener): + def __init__(self, *args): + self.version = 'Mozilla/5.0 (Phenny)' + urllib.request.URLopener.__init__(self, *args) + def http_error_default(self, url, fp, errcode, errmsg, headers): + return urllib.addinfourl(fp, [headers, errcode], "http:" + url) +urllib.request._urlopener = Grab() def get(uri): - if not uri.startswith('http'): - return - u = urllib.urlopen(uri) - bytes = u.read() - u.close() - return bytes + if not uri.startswith('http'): + return + u = urllib.request.urlopen(uri) + bytes = u.read().decode('utf-8') + u.close() + return bytes def head(uri): - if not uri.startswith('http'): - return - u = urllib.urlopen(uri) - info = u.info() - u.close() - return info + if not uri.startswith('http'): + return + u = urllib.request.urlopen(uri) + info = u.info() + u.close() + return info def post(uri, query): - if not uri.startswith('http'): - return - data = urllib.urlencode(query) - u = urllib.urlopen(uri, data) - bytes = u.read() - u.close() - return bytes + if not uri.startswith('http'): + return + data = urllib.parse.urlencode(query) + u = urllib.request.urlopen(uri, data) + bytes = u.read().decode('utf-8') + u.close() + return bytes r_entity = re.compile(r'&([^;\s]+);') def entity(match): - value = match.group(1).lower() - if value.startswith('#x'): - return unichr(int(value[2:], 16)) - elif value.startswith('#'): - return unichr(int(value[1:])) - elif name2codepoint.has_key(value): - return unichr(name2codepoint[value]) - return '[' + value + ']' + value = match.group(1).lower() + if value.startswith('#x'): + return chr(int(value[2:], 16)) + elif value.startswith('#'): + return chr(int(value[1:])) + elif value in name2codepoint: + return chr(name2codepoint[value]) + return '[' + value + ']' + +def quote(text): + return urllib.parse.quote(text) def decode(html): - return r_entity.sub(entity, html) + return r_entity.sub(entity, html) r_string = re.compile(r'("(\\.|[^"\\])*")') r_json = re.compile(r'^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]+$') env = {'__builtins__': None, 'null': None, 'true': True, 'false': False} def json(text): - """Evaluate JSON text safely (we hope).""" - if r_json.match(r_string.sub('', text)): - text = r_string.sub(lambda m: 'u' + m.group(1), text) - return eval(text.strip(' \t\r\n'), env, {}) - raise ValueError('Input must be serialised JSON.') + """Evaluate JSON text safely (we hope).""" + return jsonlib.loads(text) if __name__=="__main__": - main() + main()