diff --git a/bot.py b/bot.py index cba5594..3808710 100755 --- a/bot.py +++ b/bot.py @@ -1,7 +1,7 @@ #!/usr/bin/env python import os -import Queue +import queue import sys import traceback import time @@ -21,7 +21,7 @@ def main(): sys.path += ['lib'] os.chdir(sys.path[0] or '.') # do stuff relative to the install directory - print 'Loading plugins' + print('Loading plugins') # bootstrap the reloader eval(compile(open(os.path.join('core', 'reload.py'), 'U').read(), @@ -29,30 +29,30 @@ def main(): globals()) reload(init=True) - print 'Connecting to IRC' + print('Connecting to IRC') try: config() if not hasattr(bot, 'config'): exit() - except Exception, e: - print 'ERROR: malformed config file:', e + except Exception as e: + print('ERROR: malformed config file:', e) traceback.print_exc() sys.exit() - print 'Running main loop' + print('Running main loop') while True: reload() # these functions only do things config() # if changes have occured - for conn in bot.conns.itervalues(): + for conn in bot.conns.values(): try: out = conn.out.get_nowait() main(conn, out) - except Queue.Empty: + except queue.Empty: pass - while all(conn.out.empty() for conn in bot.conns.itervalues()): + while all(conn.out.empty() for conn in bot.conns.values()): time.sleep(.1) if __name__ == '__main__': diff --git a/core/config.py b/core/config.py index f92b16a..c62384a 100644 --- a/core/config.py +++ b/core/config.py @@ -46,7 +46,7 @@ def config(): try: bot.config = json.load(open('config')) bot._config_mtime = config_mtime - for name, conf in bot.config['connections'].iteritems(): + for name, conf in bot.config['connections'].items(): if name in bot.conns: bot.conns[name].set_conf(conf) else: @@ -54,8 +54,8 @@ def config(): bot.conns[name] = SSLIRC(conf) else: bot.conns[name] = IRC(conf) - except ValueError, e: - print 'ERROR: malformed config!', e + except ValueError as e: + print('ERROR: malformed config!', e) bot._config_mtime = 0 diff --git a/core/irc.py b/core/irc.py index a0a98ba..ff44327 100644 --- a/core/irc.py +++ b/core/irc.py @@ -1,8 +1,8 @@ import re import socket import time -import thread -import Queue +import _thread +import queue from ssl import wrap_socket, CERT_NONE, CERT_REQUIRED, SSLError @@ -20,7 +20,7 @@ def censor(text): text = text.replace('\n', '').replace('\r', '') replacement = '[censored]' if 'censored_strings' in bot.config: - words = map(re.escape, bot.config['censored_strings']) + words = list(map(re.escape, bot.config['censored_strings'])) regex = re.compile('(%s)' % "|".join(words)) text = regex.sub(replacement, text) return text @@ -33,8 +33,8 @@ class crlf_tcp(object): def __init__(self, host, port, timeout=300): self.ibuffer = "" self.obuffer = "" - self.oqueue = Queue.Queue() # lines to be sent out - self.iqueue = Queue.Queue() # lines that were received + self.oqueue = queue.Queue() # lines to be sent out + self.iqueue = queue.Queue() # lines that were received self.socket = self.create_socket() self.host = host self.port = port @@ -45,8 +45,8 @@ class crlf_tcp(object): def run(self): self.socket.connect((self.host, self.port)) - thread.start_new_thread(self.recv_loop, ()) - thread.start_new_thread(self.send_loop, ()) + _thread.start_new_thread(self.recv_loop, ()) + _thread.start_new_thread(self.send_loop, ()) def recv_from_socket(self, nbytes): return self.socket.recv(nbytes) @@ -87,7 +87,7 @@ class crlf_tcp(object): def send_loop(self): while True: line = self.oqueue.get().splitlines()[0][:500] - print ">>> %r" % line + print(">>> %r" % line) self.obuffer += line.encode('utf-8', 'replace') + '\r\n' while self.obuffer: sent = self.socket.send(self.obuffer) @@ -133,12 +133,12 @@ class IRC(object): def __init__(self, conf): self.set_conf(conf) - self.out = Queue.Queue() # responses from the server are placed here + self.out = queue.Queue() # responses from the server are placed here # format: [rawline, prefix, command, params, # nick, user, host, paramlist, msg] self.connect() - thread.start_new_thread(self.parse_loop, ()) + _thread.start_new_thread(self.parse_loop, ()) def set_conf(self, conf): self.conf = conf @@ -150,7 +150,7 @@ class IRC(object): def connect(self): self.conn = self.create_connection() - thread.start_new_thread(self.conn.run, ()) + _thread.start_new_thread(self.conn.run, ()) self.cmd("NICK", [self.nick]) self.cmd("USER", [self.conf.get('user', 'h'), "3", "*", self.conf.get('realname', @@ -203,18 +203,18 @@ class FakeIRC(IRC): def __init__(self, conf): self.set_conf(conf) - self.out = Queue.Queue() # responses from the server are placed here + self.out = queue.Queue() # responses from the server are placed here self.f = open(fn, 'rb') - thread.start_new_thread(self.parse_loop, ()) + _thread.start_new_thread(self.parse_loop, ()) def parse_loop(self): while True: msg = decode(self.f.readline()[9:]) if msg == '': - print "!!!!DONE READING FILE!!!!" + print("!!!!DONE READING FILE!!!!") return if msg.startswith(":"): # has a prefix diff --git a/core/main.py b/core/main.py index dc72e1e..460f3a7 100644 --- a/core/main.py +++ b/core/main.py @@ -1,9 +1,9 @@ import fuckit -import thread +import _thread import traceback -thread.stack_size(1024 * 512) # reduce vm size +_thread.stack_size(1024 * 512) # reduce vm size class Input(dict): @@ -81,14 +81,14 @@ def run(func, input): else: out = func(input.inp) if out is not None: - input.reply(unicode(out)) + input.reply(str(out)) def do_sieve(sieve, bot, input, func, type, args): try: return sieve(bot, input, func, type, args) except Exception: - print 'sieve error', + print('sieve error', end=' ') traceback.print_exc() return None @@ -100,7 +100,7 @@ class Handler(object): def __init__(self, func): self.func = func self.input_queue = Queue.Queue() - thread.start_new_thread(self.start, ()) + _thread.start_new_thread(self.start, ()) def start(self): uses_db = 'db' in self.func._args @@ -151,14 +151,14 @@ def dispatch(input, kind, func, args, autohelp=False): if func._thread: bot.threads[func].put(input) else: - thread.start_new_thread(run, (func, input)) + _thread.start_new_thread(run, (func, input)) def match_command(command): commands = list(bot.commands) # do some fuzzy matching - prefix = filter(lambda x: x.startswith(command), commands) + prefix = [x for x in commands if x.startswith(command)] if len(prefix) == 1: return prefix[0] elif prefix and command not in prefix: diff --git a/core/reload.py b/core/reload.py index cd0e01d..8b711d2 100644 --- a/core/reload.py +++ b/core/reload.py @@ -14,7 +14,7 @@ if 'lastfiles' not in globals(): def make_signature(f): - return f.func_code.co_filename, f.func_name, f.func_code.co_firstlineno + return f.__code__.co_filename, f.__name__, f.__code__.co_firstlineno def format_plug(plug, kind='', lpad=0, width=40): @@ -63,14 +63,14 @@ def reload(init=False): fileset = set(glob.glob(os.path.join('plugins', '*.py'))) # remove deleted/moved plugins - for name, data in bot.plugs.iteritems(): + for name, data in bot.plugs.items(): bot.plugs[name] = [x for x in data if x[0]._filename in fileset] for filename in list(mtimes): if filename not in fileset and filename not in core_fileset: mtimes.pop(filename) - for func, handler in list(bot.threads.iteritems()): + for func, handler in list(bot.threads.items()): if func._filename not in fileset: handler.stop() del bot.threads[func] @@ -92,16 +92,16 @@ def reload(init=False): continue # remove plugins already loaded from this filename - for name, data in bot.plugs.iteritems(): + for name, data in bot.plugs.items(): bot.plugs[name] = [x for x in data if x[0]._filename != filename] - for func, handler in list(bot.threads.iteritems()): + for func, handler in list(bot.threads.items()): if func._filename == filename: handler.stop() del bot.threads[func] - for obj in namespace.itervalues(): + for obj in namespace.values(): if hasattr(obj, '_hook'): # check for magic if obj._thread: bot.threads[obj] = Handler(obj) @@ -110,21 +110,21 @@ def reload(init=False): bot.plugs[type] += [data] if not init: - print '### new plugin (type: %s) loaded:' % \ - type, format_plug(data) + print('### new plugin (type: %s) loaded:' % \ + type, format_plug(data)) if changed: bot.commands = {} for plug in bot.plugs['command']: name = plug[1]['name'].lower() if not re.match(r'^\w+$', name): - print '### ERROR: invalid command name "%s" (%s)' % (name, - format_plug(plug)) + print('### ERROR: invalid command name "%s" (%s)' % (name, + format_plug(plug))) continue if name in bot.commands: - print "### ERROR: command '%s' already registered (%s, %s)" % \ + print("### ERROR: command '%s' already registered (%s, %s)" % \ (name, format_plug(bot.commands[name]), - format_plug(plug)) + format_plug(plug))) continue bot.commands[name] = plug @@ -134,28 +134,28 @@ def reload(init=False): bot.events[event].append((func, args)) if init: - print ' plugin listing:' + print(' plugin listing:') if bot.commands: # hack to make commands with multiple aliases # print nicely - print ' command:' + print(' command:') commands = collections.defaultdict(list) - for name, (func, args) in bot.commands.iteritems(): + for name, (func, args) in bot.commands.items(): commands[make_signature(func)].append(name) - for sig, names in sorted(commands.iteritems()): + for sig, names in sorted(commands.items()): names.sort(key=lambda x: (-len(x), x)) # long names first out = ' ' * 6 + '%s:%s:%s' % sig out += ' ' * (50 - len(out)) + ', '.join(names) - print out + print(out) - for kind, plugs in sorted(bot.plugs.iteritems()): + for kind, plugs in sorted(bot.plugs.items()): if kind == 'command': continue - print ' %s:' % kind + print(' %s:' % kind) for plug in plugs: - print format_plug(plug, kind=kind, lpad=6) - print + print(format_plug(plug, kind=kind, lpad=6)) + print() diff --git a/plugins/bobross.py b/plugins/bobross.py index 5daf36b..82c8ae2 100644 --- a/plugins/bobross.py +++ b/plugins/bobross.py @@ -6,7 +6,7 @@ import json quotes = [] with open("./plugins/data/bobross.json", "r") as fin: - print fin + print(fin) quotes = json.load(fin) @hook.regex("^[Bb]ob [Rr]oss fact$") diff --git a/plugins/help.py b/plugins/help.py index 5ff9992..bc5223e 100644 --- a/plugins/help.py +++ b/plugins/help.py @@ -10,7 +10,7 @@ def help(inp, bot=None, pm=None): funcs = {} disabled = bot.config.get('disabled_plugins', []) disabled_comm = bot.config.get('disabled_commands', []) - for command, (func, args) in bot.commands.iteritems(): + for command, (func, args) in bot.commands.items(): fn = re.match(r'^plugins.(.+).py$', func._filename) if fn.group(1).lower() not in disabled: if command not in disabled_comm: @@ -21,7 +21,7 @@ def help(inp, bot=None, pm=None): else: funcs[func] = command - commands = dict((value, key) for key, value in funcs.iteritems()) + commands = dict((value, key) for key, value in funcs.items()) if not inp: pm('available commands: ' + ' '.join(sorted(commands))) diff --git a/plugins/log.py b/plugins/log.py index c4d9525..2f1ce4e 100644 --- a/plugins/log.py +++ b/plugins/log.py @@ -100,4 +100,4 @@ def log(paraml, input=None, bot=None): fd = get_log_fd(bot.persist_dir, input.server, input.chan) fd.write(timestamp + ' ' + beau + '\n') - print timestamp, input.chan, beau.encode('utf8', 'ignore') + print(timestamp, input.chan, beau.encode('utf8', 'ignore')) diff --git a/plugins/pony.py b/plugins/pony.py index 05117d6..4ecacbd 100644 --- a/plugins/pony.py +++ b/plugins/pony.py @@ -7,7 +7,7 @@ import ponyapi def get_time(ep): now = datetime.datetime(2006, 1, 1) now = now.now() - then = now.fromtimestamp(int(ep[u"air_date"])) + then = now.fromtimestamp(int(ep["air_date"])) td = then-now return now, then, td @@ -21,15 +21,15 @@ def when(inp, say=None): seasonep = "" if inp == "discord": - return "%s will air on %s" % (ep[u"name"], DDate(then)) + return "%s will air on %s" % (ep["name"], DDate(then)) - if ep[u"is_movie"]: + if ep["is_movie"]: seasonep = "(a movie)" else: - seasonep = "(season %d episode %d)" % (ep[u"season"], ep[u"episode"]) + seasonep = "(season %d episode %d)" % (ep["season"], ep["episode"]) reply = "%s %s will air on %s in %d days!" % ( - ep[u"name"], seasonep, then.strftime("%a, %d %b %Y %H:%M:%S"), + ep["name"], seasonep, then.strftime("%a, %d %b %Y %H:%M:%S"), td.days) return reply @@ -41,9 +41,9 @@ def randomep(inp): seasonep = "" - if ep[u"is_movie"]: + if ep["is_movie"]: seasonep = "(a movie)" else: - seasonep = "(season %d episode %d)" % (ep[u"season"], ep[u"episode"]) + seasonep = "(season %d episode %d)" % (ep["season"], ep["episode"]) - return "%s %s" % (ep[u"name"], seasonep) + return "%s %s" % (ep["name"], seasonep) diff --git a/plugins/sieve.py b/plugins/sieve.py index 7180998..acdb21f 100644 --- a/plugins/sieve.py +++ b/plugins/sieve.py @@ -28,11 +28,11 @@ def sieve_suite(bot, input, func, kind, args): if acl is None: continue if 'deny-except' in acl: - allowed_channels = map(unicode.lower, acl['deny-except']) + allowed_channels = list(map(str.lower, acl['deny-except'])) if input.chan.lower() not in allowed_channels: return None if 'allow-except' in acl: - denied_channels = map(unicode.lower, acl['allow-except']) + denied_channels = list(map(str.lower, acl['allow-except'])) if input.chan.lower() in denied_channels: return None if 'whitelist' in acl: diff --git a/plugins/tinyurl.py b/plugins/tinyurl.py index 8c6c7f5..1276e60 100644 --- a/plugins/tinyurl.py +++ b/plugins/tinyurl.py @@ -5,5 +5,5 @@ from util import hook, http def tinyurl(match): try: return http.open(match.group()).url.strip() - except http.URLError, e: + except http.URLError as e: pass diff --git a/plugins/urbit.py b/plugins/urbit.py index ded1c33..cec8119 100644 --- a/plugins/urbit.py +++ b/plugins/urbit.py @@ -8,7 +8,7 @@ prefix = split_len(names, 3) suffix = split_len(endings, 3) def ipv4tourbit(ip): - ip = map(lambda x: int(x), ip.split(".")) + ip = [int(x) for x in ip.split(".")] return "~%s%s-%s%s" % (prefix[ip[0]], suffix[ip[1]], prefix[ip[2]], suffix[ip[3]]) diff --git a/plugins/urlhistory.py b/plugins/urlhistory.py index 37c1f4b..5cb8092 100644 --- a/plugins/urlhistory.py +++ b/plugins/urlhistory.py @@ -29,7 +29,7 @@ def get_history(db, chan, url): def nicklist(nicks): - nicks = sorted(dict(nicks), key=unicode.lower) + nicks = sorted(dict(nicks), key=str.lower) if len(nicks) <= 2: return ' and '.join(nicks) else: diff --git a/plugins/util/hook.py b/plugins/util/hook.py index 349eac6..099259e 100644 --- a/plugins/util/hook.py +++ b/plugins/util/hook.py @@ -8,7 +8,7 @@ def _hook_add(func, add, name=''): func._hook.append(add) if not hasattr(func, '_filename'): - func._filename = func.func_code.co_filename + func._filename = func.__code__.co_filename if not hasattr(func, '_args'): argspec = inspect.getargspec(func) @@ -39,7 +39,7 @@ def _hook_add(func, add, name=''): def sieve(func): - if func.func_code.co_argcount != 5: + if func.__code__.co_argcount != 5: raise ValueError( 'sieves must take 5 arguments: (bot, input, func, type, args)') _hook_add(func, ['sieve', (func,)]) @@ -50,7 +50,7 @@ def command(arg=None, **kwargs): args = {} def command_wrapper(func): - args.setdefault('name', func.func_name) + args.setdefault('name', func.__name__) _hook_add(func, ['command', (func, args)], 'command') return func @@ -67,7 +67,7 @@ def event(arg=None, **kwargs): args = kwargs def event_wrapper(func): - args['name'] = func.func_name + args['name'] = func.__name__ args.setdefault('events', ['*']) _hook_add(func, ['event', (func, args)], 'event') return func @@ -96,7 +96,7 @@ def regex(regex, flags=0, **kwargs): args = kwargs def regex_wrapper(func): - args['name'] = func.func_name + args['name'] = func.__name__ args['regex'] = regex args['re'] = re.compile(regex, flags) _hook_add(func, ['regex', (func, args)], 'regex') diff --git a/plugins/util/http.py b/plugins/util/http.py index 91759e4..327010e 100644 --- a/plugins/util/http.py +++ b/plugins/util/http.py @@ -1,18 +1,18 @@ # convenience wrapper for urllib2 & friends import binascii -import cookielib +import http.cookiejar import hmac import json import random import string import time -import urllib -import urllib2 -import urlparse +import urllib.request, urllib.parse, urllib.error +import urllib.request, urllib.error, urllib.parse +import urllib.parse from hashlib import sha1 -from urllib import quote, unquote, quote_plus as _quote_plus -from urllib2 import HTTPError, URLError +from urllib.parse import quote, unquote, quote_plus as _quote_plus +from urllib.error import HTTPError, URLError from lxml import etree, html @@ -23,7 +23,7 @@ ua_firefox = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) ' \ 'Gecko/20070725 Firefox/2.0.0.6' ua_internetexplorer = 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)' -jar = cookielib.CookieJar() +jar = http.cookiejar.CookieJar() def get(*args, **kwargs): @@ -51,13 +51,13 @@ def open(url, query_params=None, post_data=None, url = prepare_url(url, query_params) - request = urllib2.Request(url, post_data) + request = urllib.request.Request(url, post_data) if get_method is not None: request.get_method = lambda: get_method if headers is not None: - for header_key, header_value in headers.iteritems(): + for header_key, header_value in headers.items(): request.add_header(header_key, header_value) if 'User-Agent' not in request.headers: @@ -78,28 +78,28 @@ def open(url, query_params=None, post_data=None, request.add_header('Authorization', header) if cookies: - opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(jar)) + opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(jar)) else: - opener = urllib2.build_opener() + opener = urllib.request.build_opener() return opener.open(request) def prepare_url(url, queries): if queries: - scheme, netloc, path, query, fragment = urlparse.urlsplit(url) + scheme, netloc, path, query, fragment = urllib.parse.urlsplit(url) - query = dict(urlparse.parse_qsl(query)) + query = dict(urllib.parse.parse_qsl(query)) query.update(queries) - query = urllib.urlencode(dict((to_utf8(key), to_utf8(value)) - for key, value in query.iteritems())) + query = urllib.parse.urlencode(dict((to_utf8(key), to_utf8(value)) + for key, value in query.items())) - url = urlparse.urlunsplit((scheme, netloc, path, query, fragment)) + url = urllib.parse.urlunsplit((scheme, netloc, path, query, fragment)) return url def to_utf8(s): - if isinstance(s, unicode): + if isinstance(s, str): return s.encode('utf8', 'ignore') else: return str(s) diff --git a/plugins/util/timesince.py b/plugins/util/timesince.py index a3cea46..5cba05e 100644 --- a/plugins/util/timesince.py +++ b/plugins/util/timesince.py @@ -69,7 +69,7 @@ def timesince(d, now=None): since = delta.days * 24 * 60 * 60 + delta.seconds if since <= 0: # d is in the future compared to now, stop processing. - return u'0 ' + 'minutes' + return '0 ' + 'minutes' for i, (seconds, name) in enumerate(chunks): count = since // seconds if count != 0: diff --git a/plugins/util/urlnorm.py b/plugins/util/urlnorm.py index 4089710..05187c5 100644 --- a/plugins/util/urlnorm.py +++ b/plugins/util/urlnorm.py @@ -25,8 +25,8 @@ __license__ = "Python" import re import unicodedata -import urlparse -from urllib import quote, unquote +import urllib.parse +from urllib.parse import quote, unquote default_port = { 'http': 80, @@ -50,7 +50,7 @@ normalizers = ( Normalizer( re.compile(r'(?:https?://)?(?:[a-zA-Z0-9\-]+\.)?(?:a def normalize(url): """Normalize a URL.""" - scheme, auth, path, query, fragment = urlparse.urlsplit(url.strip()) + scheme, auth, path, query, fragment = urllib.parse.urlsplit(url.strip()) userinfo, host, port = re.search('([^@]*@)?([^:]*):?(.*)', auth).groups() # Always provide the URI scheme in lowercase characters. @@ -73,7 +73,7 @@ def normalize(url): # Always use uppercase A-through-F characters when percent-encoding. # All portions of the URI must be utf-8 encoded NFC from Unicode strings def clean(string): - string = unicode(unquote(string), 'utf-8', 'replace') + string = str(unquote(string), 'utf-8', 'replace') return unicodedata.normalize('NFC', string).encode('utf-8') path = quote(clean(path), "~:/?#[]@!$&'()*+,;=") fragment = quote(clean(fragment), "~") @@ -112,7 +112,7 @@ def normalize(url): # For schemes that define a port, use an empty port if the default is # desired - if port and scheme in default_port.keys(): + if port and scheme in list(default_port.keys()): if port.isdigit(): port = str(int(port)) if int(port) == default_port[scheme]: @@ -124,7 +124,7 @@ def normalize(url): auth += ":" + port if url.endswith("#") and query == "" and fragment == "": path += "#" - normal_url = urlparse.urlunsplit((scheme, auth, path, query, + normal_url = urllib.parse.urlunsplit((scheme, auth, path, query, fragment)).replace("http:///", "http://") for norm in normalizers: m = norm.regex.match(normal_url)