Merge branch 'py3' into 'master'

Upgrade dr.botzo to Python 3

The py3 branch brings dr.botzo to the point that it's able to run in a Python 3.4 environment. All IRC plugins have been tested on an actual network.

Due to 2to3's behavior with unicode_literals, this should *not* be run in a Python 2 environment, as the once-unicode-safe literals might be mistreated again.

See merge request !1
This commit is contained in:
Brian S. Stephan 2016-01-16 19:47:01 -06:00
commit f66aea6c2d
73 changed files with 190 additions and 253 deletions

View File

@ -2,7 +2,7 @@
import logging import logging
import random import random
import thread import threading
import time import time
from irc.client import NickMask, is_channel from irc.client import NickMask, is_channel
@ -159,7 +159,9 @@ class Acro(Plugin):
self.bot.privmsg(self.game.channel, "the round has started! your acronym is '{0:s}'. " self.bot.privmsg(self.game.channel, "the round has started! your acronym is '{0:s}'. "
"submit within {1:d} seconds via !acro submit [meaning]".format(acro, sleep_time)) "submit within {1:d} seconds via !acro submit [meaning]".format(acro, sleep_time))
thread.start_new_thread(self.thread_do_process_submissions, (sleep_time,)) t = threading.Thread(target=self.thread_do_process_submissions, args=(sleep_time,))
t.daemon = True
t.start()
@staticmethod @staticmethod
def _generate_acro(): def _generate_acro():
@ -254,12 +256,14 @@ class Acro(Plugin):
"""Begin the voting period.""" """Begin the voting period."""
self.game.state = 3 self.game.state = 3
self.game.rounds[-1].sub_shuffle = self.game.rounds[-1].submissions.keys() self.game.rounds[-1].sub_shuffle = list(self.game.rounds[-1].submissions.keys())
random.shuffle(self.game.rounds[-1].sub_shuffle) random.shuffle(self.game.rounds[-1].sub_shuffle)
self.bot.privmsg(self.game.channel, "here are the results. vote with !acro vote [number]") self.bot.privmsg(self.game.channel, "here are the results. vote with !acro vote [number]")
self._print_round_acros() self._print_round_acros()
thread.start_new_thread(self.thread_do_process_votes, ()) t = threading.Thread(target=self.thread_do_process_votes, args=())
t.daemon = True
t.start()
def _print_round_acros(self): def _print_round_acros(self):
"""Take the current round's acros and spit them to the channel.""" """Take the current round's acros and spit them to the channel."""
@ -303,17 +307,17 @@ class Acro(Plugin):
"""For the acros in the round, find the votes for them.""" """For the acros in the round, find the votes for them."""
i = 0 i = 0
for s in self.game.rounds[-1].submissions.keys(): for s in list(self.game.rounds[-1].submissions.keys()):
votes = filter(lambda x: x == s, self.game.rounds[-1].votes.values()) votes = [x for x in list(self.game.rounds[-1].votes.values()) if x == s]
self.bot.privmsg(self.game.channel, " {0:d} ({1:s}): {2:d}".format(i+1, s, len(votes))) self.bot.privmsg(self.game.channel, " {0:d} ({1:s}): {2:d}".format(i+1, s, len(votes)))
i += 1 i += 1
def _add_round_scores_to_game_scores(self): def _add_round_scores_to_game_scores(self):
"""Apply the final round scores to the totall scores for the game.""" """Apply the final round scores to the totall scores for the game."""
for s in self.game.rounds[-1].votes.values(): for s in list(self.game.rounds[-1].votes.values()):
votes = filter(lambda x: x == s, self.game.rounds[-1].votes.values()) votes = [x for x in list(self.game.rounds[-1].votes.values()) if x == s]
if s in self.game.scores.keys(): if s in list(self.game.scores.keys()):
self.game.scores[s] += len(votes) self.game.scores[s] += len(votes)
else: else:
self.game.scores[s] = len(votes) self.game.scores[s] = len(votes)
@ -338,7 +342,7 @@ class Acro(Plugin):
def _print_game_scores(self): def _print_game_scores(self):
"""Print the final calculated scores.""" """Print the final calculated scores."""
for s in self.game.scores.keys(): for s in list(self.game.scores.keys()):
self.bot.privmsg(self.game.channel, " {0:s}: {1:d}".format(s, self.game.scores[s])) self.bot.privmsg(self.game.channel, " {0:s}: {1:d}".format(s, self.game.scores[s]))

View File

@ -1,7 +1,5 @@
"""Access to countdown items through bot commands.""" """Access to countdown items through bot commands."""
from __future__ import unicode_literals
import logging import logging
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,7 +1,5 @@
"""Countdown item models.""" """Countdown item models."""
from __future__ import unicode_literals
import logging import logging
from django.db import models from django.db import models
@ -20,7 +18,7 @@ class CountdownItem(models.Model):
created_time = models.DateTimeField(auto_now_add=True) created_time = models.DateTimeField(auto_now_add=True)
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return "{0:s} @ {1:s}".format(self.name, timezone.localtime(self.at_time).strftime('%Y-%m-%d %H:%M:%S %Z')) return "{0:s} @ {1:s}".format(self.name, timezone.localtime(self.at_time).strftime('%Y-%m-%d %H:%M:%S %Z'))

View File

@ -187,7 +187,7 @@ class DiceRoller(object):
the actual roll. Returns a string representing the result. the actual roll. Returns a string representing the result.
""" """
a = range(dice) a = list(range(dice))
for i in range(dice): for i in range(dice):
a[i] = random.randint(1, size) a[i] = random.randint(1, size)
if keep != dice: if keep != dice:

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,7 +1,5 @@
"""Track dispatcher configurations.""" """Track dispatcher configurations."""
from __future__ import unicode_literals
import logging import logging
from django.db import models from django.db import models
@ -21,7 +19,7 @@ class Dispatcher(models.Model):
('send_message', "Can send messages to dispatchers"), ('send_message', "Can send messages to dispatchers"),
) )
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return "{0:s}".format(self.key) return "{0:s}".format(self.key)
@ -44,7 +42,7 @@ class DispatcherAction(models.Model):
destination = models.CharField(max_length=200) destination = models.CharField(max_length=200)
include_key = models.BooleanField(default=False) include_key = models.BooleanField(default=False)
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return "{0:s} -> {1:s} {2:s}".format(self.dispatcher.key, self.type, self.destination) return "{0:s} -> {1:s} {2:s}".format(self.dispatcher.key, self.type, self.destination)

View File

@ -1,11 +1,9 @@
"""Handle dispatcher API requests.""" """Handle dispatcher API requests."""
from __future__ import unicode_literals
import copy import copy
import logging import logging
import os import os
import xmlrpclib import xmlrpc.client
from django.conf import settings from django.conf import settings
from rest_framework import generics, status from rest_framework import generics, status
@ -79,7 +77,7 @@ class DispatchMessage(generics.GenericAPIView):
# connect over XML-RPC and send # connect over XML-RPC and send
try: try:
bot_url = 'http://{0:s}:{1:d}/'.format(settings.IRCBOT_XMLRPC_HOST, settings.IRCBOT_XMLRPC_PORT) bot_url = 'http://{0:s}:{1:d}/'.format(settings.IRCBOT_XMLRPC_HOST, settings.IRCBOT_XMLRPC_PORT)
bot = xmlrpclib.ServerProxy(bot_url) bot = xmlrpc.client.ServerProxy(bot_url)
log.debug("sending '%s' to channel %s", text, action.destination) log.debug("sending '%s' to channel %s", text, action.destination)
bot.privmsg(action.destination, text) bot.privmsg(action.destination, text)
except Exception as e: except Exception as e:

View File

@ -1,4 +1,4 @@
from __future__ import unicode_literals """IRC plugin for retrieval of facts."""
import logging import logging

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations
import datetime import datetime

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,7 +1,5 @@
"""Store "facts".""" """Store "facts"."""
from __future__ import unicode_literals
import logging import logging
import random import random
@ -21,7 +19,7 @@ class FactCategory(models.Model):
class Meta: class Meta:
verbose_name_plural = 'fact categories' verbose_name_plural = 'fact categories'
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return "{0:s}".format(self.name) return "{0:s}".format(self.name)
@ -60,7 +58,7 @@ class Fact(models.Model):
objects = FactManager() objects = FactManager()
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return "{0:s} - {1:s}".format(self.category.name, self.fact) return "{0:s} - {1:s}".format(self.category.name, self.fact)

View File

@ -1,9 +1,7 @@
"""Manage ircbot models and admin actions in the admin interface.""" """Manage ircbot models and admin actions in the admin interface."""
from __future__ import unicode_literals
import logging import logging
import xmlrpclib import xmlrpc.client
from django.conf import settings from django.conf import settings
from django.contrib import admin from django.contrib import admin
@ -32,7 +30,7 @@ def send_privmsg(request):
message = form.cleaned_data['message'] message = form.cleaned_data['message']
bot_url = 'http://{0:s}:{1:d}/'.format(settings.IRCBOT_XMLRPC_HOST, settings.IRCBOT_XMLRPC_PORT) bot_url = 'http://{0:s}:{1:d}/'.format(settings.IRCBOT_XMLRPC_HOST, settings.IRCBOT_XMLRPC_PORT)
bot = xmlrpclib.ServerProxy(bot_url) bot = xmlrpc.client.ServerProxy(bot_url)
bot.privmsg(target, message) bot.privmsg(target, message)
form = PrivmsgForm() form = PrivmsgForm()
else: else:

View File

@ -1,17 +1,15 @@
"""Provide the base IRC client bot which other code can latch onto.""" """Provide the base IRC client bot which other code can latch onto."""
from __future__ import unicode_literals
import bisect import bisect
import collections import collections
import copy import copy
import logging import logging
import re import re
from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
import socket import socket
import ssl import ssl
import sys import sys
import thread import threading
import time import time
from django.conf import settings from django.conf import settings
@ -106,7 +104,7 @@ class DrReactor(irc.client.Reactor):
handler = PrioritizedRegexHandler(priority, regex, handler) handler = PrioritizedRegexHandler(priority, regex, handler)
for event in events: for event in events:
with self.mutex: with self.mutex:
log.debug(u"in add_global_regex_handler") log.debug("in add_global_regex_handler")
event_regex_handlers = self.regex_handlers.setdefault(event, []) event_regex_handlers = self.regex_handlers.setdefault(event, [])
bisect.insort(event_regex_handlers, handler) bisect.insort(event_regex_handlers, handler)
@ -149,7 +147,7 @@ class DrReactor(irc.client.Reactor):
# only do aliasing for pubmsg/privmsg # only do aliasing for pubmsg/privmsg
if event.type in ['pubmsg', 'privmsg']: if event.type in ['pubmsg', 'privmsg']:
what = event.arguments[0] what = event.arguments[0]
log.debug(u"checking for alias for %s", what) log.debug("checking for alias for %s", what)
for alias in Alias.objects.all(): for alias in Alias.objects.all():
repl = alias.replace(what) repl = alias.replace(what)
@ -161,18 +159,18 @@ class DrReactor(irc.client.Reactor):
with self.mutex: with self.mutex:
# doing regex version first as it has the potential to be more specific # doing regex version first as it has the potential to be more specific
log.debug(u"checking regex handlers for %s", event.type) log.debug("checking regex handlers for %s", event.type)
matching_handlers = sorted( matching_handlers = sorted(
self.regex_handlers.get("all_events", []) + self.regex_handlers.get("all_events", []) +
self.regex_handlers.get(event.type, []) self.regex_handlers.get(event.type, [])
) )
log.debug(u"got %d", len(matching_handlers)) log.debug("got %d", len(matching_handlers))
for handler in matching_handlers: for handler in matching_handlers:
log.debug(u"checking %s vs. %s", handler, event.arguments) log.debug("checking %s vs. %s", handler, event.arguments)
for line in event.arguments: for line in event.arguments:
match = re.search(handler.regex, line) match = re.search(handler.regex, line)
if match: if match:
log.debug(u"match!") log.debug("match!")
result = handler.callback(connection, event, match) result = handler.callback(connection, event, match)
if result == "NO MORE": if result == "NO MORE":
return return
@ -182,7 +180,7 @@ class DrReactor(irc.client.Reactor):
self.handlers.get(event.type, []) self.handlers.get(event.type, [])
) )
for handler in matching_handlers: for handler in matching_handlers:
log.debug(u"not-match") log.debug("not-match")
result = handler.callback(connection, event) result = handler.callback(connection, event)
if result == "NO MORE": if result == "NO MORE":
return return
@ -204,14 +202,14 @@ class DrReactor(irc.client.Reactor):
""" """
log.debug(u"RECURSING EVENT: e[%s] s[%s] t[%s] a[%s]", event.type, event.source, log.debug("RECURSING EVENT: e[%s] s[%s] t[%s] a[%s]", event.type, event.source,
event.target, event.arguments) event.target, event.arguments)
try: try:
# begin recursion search # begin recursion search
attempt = event.arguments[0] attempt = event.arguments[0]
log.debug(u"checking it against %s", attempt) log.debug("checking it against %s", attempt)
start_idx = attempt.find('[') start_idx = attempt.find('[')
subcmd = attempt[start_idx+1:] subcmd = attempt[start_idx+1:]
@ -219,7 +217,7 @@ class DrReactor(irc.client.Reactor):
subcmd = subcmd[:end_idx] subcmd = subcmd[:end_idx]
if start_idx != -1 and end_idx != -1 and len(subcmd) > 0: if start_idx != -1 and end_idx != -1 and len(subcmd) > 0:
log.debug(u"subcmd: %s", subcmd) log.debug("subcmd: %s", subcmd)
# found recursion candidate # found recursion candidate
# copy the event and see if IT has recursion to do # copy the event and see if IT has recursion to do
@ -227,7 +225,7 @@ class DrReactor(irc.client.Reactor):
newevent.arguments[0] = subcmd newevent.arguments[0] = subcmd
newevent._recursing = True newevent._recursing = True
log.debug(u"new event copied") log.debug("new event copied")
self.try_recursion(connection, newevent) self.try_recursion(connection, newevent)
@ -243,7 +241,7 @@ class DrReactor(irc.client.Reactor):
# event's [] section with it. # event's [] section with it.
oldtext = event.arguments[0] oldtext = event.arguments[0]
newtext = oldtext.replace('['+subcmd+']', newevent.arguments[0]) newtext = oldtext.replace('['+subcmd+']', newevent.arguments[0])
log.debug(u"oldtext: '%s' newtext: '%s'", oldtext, newtext) log.debug("oldtext: '%s' newtext: '%s'", oldtext, newtext)
event.arguments[0] = newtext event.arguments[0] = newtext
# we have now resolved the []. recursion will unfold, replacing # we have now resolved the []. recursion will unfold, replacing
@ -251,9 +249,9 @@ class DrReactor(irc.client.Reactor):
# original irc event in _handle_event, which will do one # original irc event in _handle_event, which will do one
# last search on the text. # last search on the text.
else: else:
log.debug(u"no more recursion here") log.debug("no more recursion here")
except IndexError: except IndexError:
log.debug(u"no more recursion here") log.debug("no more recursion here")
def try_to_replace_event_text_with_module_text(self, connection, event): def try_to_replace_event_text_with_module_text(self, connection, event):
"""Do something very similar to _handle_event, but for recursion. """Do something very similar to _handle_event, but for recursion.
@ -272,7 +270,7 @@ class DrReactor(irc.client.Reactor):
# only do aliasing for pubmsg/privmsg # only do aliasing for pubmsg/privmsg
if event.type in ['pubmsg', 'privmsg']: if event.type in ['pubmsg', 'privmsg']:
what = event.arguments[0] what = event.arguments[0]
log.debug(u"checking for (recursion) alias for %s", what) log.debug("checking for (recursion) alias for %s", what)
for alias in Alias.objects.all(): for alias in Alias.objects.all():
repl = alias.replace(what) repl = alias.replace(what)
@ -282,22 +280,22 @@ class DrReactor(irc.client.Reactor):
with self.mutex: with self.mutex:
# doing regex version first as it has the potential to be more specific # doing regex version first as it has the potential to be more specific
log.debug(u"checking (recursion) regex handlers for %s", event.type) log.debug("checking (recursion) regex handlers for %s", event.type)
matching_handlers = sorted( matching_handlers = sorted(
self.regex_handlers.get("all_events", []) + self.regex_handlers.get("all_events", []) +
self.regex_handlers.get(event.type, []) self.regex_handlers.get(event.type, [])
) )
log.debug(u"got %d", len(matching_handlers)) log.debug("got %d", len(matching_handlers))
for handler in matching_handlers: for handler in matching_handlers:
log.debug(u"checking (recursion) %s vs. %s", handler, event.arguments) log.debug("checking (recursion) %s vs. %s", handler, event.arguments)
for line in event.arguments: for line in event.arguments:
match = re.search(handler.regex, line) match = re.search(handler.regex, line)
if match: if match:
log.debug(u"match (recursion)!") log.debug("match (recursion)!")
result = handler.callback(connection, event, match) result = handler.callback(connection, event, match)
log.debug(u"result: %s", result) log.debug("result: %s", result)
if result: if result:
log.debug(u"appending %s to replies", result) log.debug("appending %s to replies", result)
replies.append(result) replies.append(result)
matching_handlers = sorted( matching_handlers = sorted(
@ -305,11 +303,11 @@ class DrReactor(irc.client.Reactor):
self.handlers.get(event.type, []) self.handlers.get(event.type, [])
) )
for handler in matching_handlers: for handler in matching_handlers:
log.debug(u"not-match (recursion)") log.debug("not-match (recursion)")
result = handler.callback(connection, event) result = handler.callback(connection, event)
log.debug(u"result: %s", result) log.debug("result: %s", result)
if result: if result:
log.debug(u"appending %s to replies", result) log.debug("appending %s to replies", result)
replies.append(result) replies.append(result)
if len(replies): if len(replies):
@ -364,7 +362,9 @@ class IRCBot(irc.client.SimpleIRCClient):
requestHandler=IrcBotXMLRPCRequestHandler, allow_none=True) requestHandler=IrcBotXMLRPCRequestHandler, allow_none=True)
self.xmlrpc.register_introspection_functions() self.xmlrpc.register_introspection_functions()
thread.start_new_thread(self._xmlrpc_listen, ()) t = threading.Thread(target=self._xmlrpc_listen, args=())
t.daemon = True
t.start()
# register XML-RPC stuff # register XML-RPC stuff
self.xmlrpc.register_function(self.privmsg, 'privmsg') self.xmlrpc.register_function(self.privmsg, 'privmsg')
@ -457,7 +457,7 @@ class IRCBot(irc.client.SimpleIRCClient):
def _on_nick(self, c, e): def _on_nick(self, c, e):
before = e.source.nick before = e.source.nick
after = e.target after = e.target
for ch in self.channels.values(): for ch in list(self.channels.values()):
if ch.has_user(before): if ch.has_user(before):
ch.change_nick(before, after) ch.change_nick(before, after)
@ -472,7 +472,7 @@ class IRCBot(irc.client.SimpleIRCClient):
def _on_quit(self, c, e): def _on_quit(self, c, e):
nick = e.source.nick nick = e.source.nick
for ch in self.channels.values(): for ch in list(self.channels.values()):
if ch.has_user(nick): if ch.has_user(nick):
ch.remove_user(nick) ch.remove_user(nick)
@ -501,11 +501,11 @@ class IRCBot(irc.client.SimpleIRCClient):
time.sleep(settings.IRCBOT_SLEEP_BEFORE_AUTOJOIN_SECONDS) time.sleep(settings.IRCBOT_SLEEP_BEFORE_AUTOJOIN_SECONDS)
for chan in IrcChannel.objects.filter(autojoin=True): for chan in IrcChannel.objects.filter(autojoin=True):
log.info(u"autojoining %s", chan.name) log.info("autojoining %s", chan.name)
self.connection.join(chan) self.connection.join(chan)
for plugin in IrcPlugin.objects.filter(autoload=True): for plugin in IrcPlugin.objects.filter(autoload=True):
log.info(u"autoloading %s", plugin.path) log.info("autoloading %s", plugin.path)
self._load_plugin(connection, event, plugin.path, feedback=False) self._load_plugin(connection, event, plugin.path, feedback=False)
match = re.search(r'(\S+!\S+@\S+)', what) match = re.search(r'(\S+!\S+@\S+)', what)
@ -579,10 +579,10 @@ class IRCBot(irc.client.SimpleIRCClient):
"""Handle IRC requests to load a plugin.""" """Handle IRC requests to load a plugin."""
has_perm = ircbotlib.has_permission(event.source, 'ircbot.manage_loaded_plugins') has_perm = ircbotlib.has_permission(event.source, 'ircbot.manage_loaded_plugins')
log.debug(u"has permission to load?: %s", str(has_perm)) log.debug("has permission to load?: %s", str(has_perm))
if has_perm: if has_perm:
plugin_path = match.group(1) plugin_path = match.group(1)
log.debug(u"calling _load_plugin on %s", plugin_path) log.debug("calling _load_plugin on %s", plugin_path)
self._load_plugin(connection, event, plugin_path) self._load_plugin(connection, event, plugin_path)
def _load_plugin(self, connection, event, plugin_path, feedback=True): def _load_plugin(self, connection, event, plugin_path, feedback=True):
@ -591,7 +591,7 @@ class IRCBot(irc.client.SimpleIRCClient):
The general assumption here is that a plugin's init loads its hooks and handlers. The general assumption here is that a plugin's init loads its hooks and handlers.
""" """
log.debug(u"trying to load %s", plugin_path) log.debug("trying to load %s", plugin_path)
dest = None dest = None
if feedback: if feedback:
@ -621,28 +621,28 @@ class IRCBot(irc.client.SimpleIRCClient):
log.exception(e) log.exception(e)
# i don't think this would get populated if __import__ failed del sys.modules[plugin_path] # i don't think this would get populated if __import__ failed del sys.modules[plugin_path]
if feedback: if feedback:
self.privmsg(dest, "Plugin '{0:s}' could not be loaded: {1:s}".format(plugin_path, e)) self.privmsg(dest, "Plugin '{0:s}' could not be loaded: {1:s}".format(plugin_path, str(e)))
except AttributeError as e: except AttributeError as e:
log.error("Error loading '{0:s}'".format(plugin_path)) log.error("Error loading '{0:s}'".format(plugin_path))
log.exception(e) log.exception(e)
del sys.modules[plugin_path] del sys.modules[plugin_path]
if feedback: if feedback:
self.privmsg(dest, "Plugin '{0:s}' could not be loaded: {1:s}".format(plugin_path, e)) self.privmsg(dest, "Plugin '{0:s}' could not be loaded: {1:s}".format(plugin_path, str(e)))
def handle_unload(self, connection, event, match): def handle_unload(self, connection, event, match):
"""Handle IRC requests to unload a plugin.""" """Handle IRC requests to unload a plugin."""
has_perm = ircbotlib.has_permission(event.source, 'ircbot.manage_loaded_plugins') has_perm = ircbotlib.has_permission(event.source, 'ircbot.manage_loaded_plugins')
log.debug(u"has permission to unload?: %s", str(has_perm)) log.debug("has permission to unload?: %s", str(has_perm))
if has_perm: if has_perm:
plugin_path = match.group(1) plugin_path = match.group(1)
log.debug(u"calling _unload_plugin on %s", plugin_path) log.debug("calling _unload_plugin on %s", plugin_path)
self._unload_plugin(connection, event, plugin_path) self._unload_plugin(connection, event, plugin_path)
def _unload_plugin(self, connection, event, plugin_path): def _unload_plugin(self, connection, event, plugin_path):
"""Attempt to unload and del a module if it's loaded.""" """Attempt to unload and del a module if it's loaded."""
log.debug(u"trying to unload %s", plugin_path) log.debug("trying to unload %s", plugin_path)
dest = ircbotlib.reply_destination_for_event(event) dest = ircbotlib.reply_destination_for_event(event)
@ -722,9 +722,9 @@ class IRCBot(irc.client.SimpleIRCClient):
"NO MORE" to stop other event handlers from acting. "NO MORE" to stop other event handlers from acting.
""" """
log.debug(u"in reply for e[%s] r[%s]", event, replystr) log.debug("in reply for e[%s] r[%s]", event, replystr)
replypath = ircbotlib.reply_destination_for_event(event) replypath = ircbotlib.reply_destination_for_event(event)
log.debug(u"replypath: %s", replypath) log.debug("replypath: %s", replypath)
if replystr is not None: if replystr is not None:
recursing = getattr(event, '_recursing', False) recursing = getattr(event, '_recursing', False)
@ -773,9 +773,9 @@ class IRCBot(irc.client.SimpleIRCClient):
def sigint_handler(self, signal, frame): def sigint_handler(self, signal, frame):
"""Cleanly shutdown on SIGINT.""" """Cleanly shutdown on SIGINT."""
log.debug(u"shutting down") log.debug("shutting down")
for path, plugin in self.plugins: for path, plugin in self.plugins:
log.debug(u"trying to shut down %s", path) log.debug("trying to shut down %s", path)
self.plugins.remove((path, plugin)) self.plugins.remove((path, plugin))
plugin.stop() plugin.stop()
del plugin del plugin
@ -798,28 +798,28 @@ class Channel(object):
def users(self): def users(self):
"""Returns an unsorted list of the channel's users.""" """Returns an unsorted list of the channel's users."""
return self.userdict.keys() return list(self.userdict.keys())
def opers(self): def opers(self):
"""Returns an unsorted list of the channel's operators.""" """Returns an unsorted list of the channel's operators."""
return self.operdict.keys() return list(self.operdict.keys())
def voiced(self): def voiced(self):
"""Returns an unsorted list of the persons that have voice """Returns an unsorted list of the persons that have voice
mode set in the channel.""" mode set in the channel."""
return self.voiceddict.keys() return list(self.voiceddict.keys())
def owners(self): def owners(self):
"""Returns an unsorted list of the channel's owners.""" """Returns an unsorted list of the channel's owners."""
return self.ownerdict.keys() return list(self.ownerdict.keys())
def halfops(self): def halfops(self):
"""Returns an unsorted list of the channel's half-operators.""" """Returns an unsorted list of the channel's half-operators."""
return self.halfopdict.keys() return list(self.halfopdict.keys())
def has_user(self, nick): def has_user(self, nick):
"""Check whether the channel has a user.""" """Check whether the channel has a user."""

View File

@ -39,7 +39,7 @@ class ChannelManagement(Plugin):
channel = match.group(1) channel = match.group(1)
# put it in the database if it isn't already # put it in the database if it isn't already
chan_mod, c = IrcChannel.objects.get_or_create(name=channel) chan_mod, c = IrcChannel.objects.get_or_create(name=channel)
log.debug(u"joining channel %s", channel) log.debug("joining channel %s", channel)
self.connection.join(channel) self.connection.join(channel)
return self.bot.reply(event, "Joined channel {0:s}.".format(channel)) return self.bot.reply(event, "Joined channel {0:s}.".format(channel))
@ -51,7 +51,7 @@ class ChannelManagement(Plugin):
channel = match.group(1) channel = match.group(1)
# put it in the database if it isn't already # put it in the database if it isn't already
chan_mod, c = IrcChannel.objects.get_or_create(name=channel) chan_mod, c = IrcChannel.objects.get_or_create(name=channel)
log.debug(u"parting channel %s", channel) log.debug("parting channel %s", channel)
self.connection.part(channel) self.connection.part(channel)
return self.bot.reply(event, "Parted channel {0:s}.".format(channel)) return self.bot.reply(event, "Parted channel {0:s}.".format(channel))

View File

@ -1,4 +1,4 @@
from __future__ import unicode_literals """Watch channel topics for changes and note them."""
import logging import logging

View File

@ -1,7 +1,5 @@
"""Library and convenience methods for the IRC bot and plugins.""" """Library and convenience methods for the IRC bot and plugins."""
from __future__ import unicode_literals
import logging import logging
import irc.client import irc.client
@ -25,17 +23,17 @@ class Plugin(object):
self.connection = connection self.connection = connection
self.event = event self.event = event
log.info(u"initialized %s", self.__class__.__name__) log.info("initialized %s", self.__class__.__name__)
def start(self): def start(self):
"""Initialization stuff here --- global handlers, configs from database, so on.""" """Initialization stuff here --- global handlers, configs from database, so on."""
log.info(u"started %s", self.__class__.__name__) log.info("started %s", self.__class__.__name__)
def stop(self): def stop(self):
"""Teardown stuff here --- unregister handlers, for example.""" """Teardown stuff here --- unregister handlers, for example."""
log.info(u"stopped %s", self.__class__.__name__) log.info("stopped %s", self.__class__.__name__)
def _unencode_xml(self, text): def _unencode_xml(self, text):
"""Convert <, >, & to their real entities.""" """Convert <, >, & to their real entities."""
@ -51,21 +49,21 @@ def has_permission(source, permission):
try: try:
bot_user = BotUser.objects.get(nickmask=source) bot_user = BotUser.objects.get(nickmask=source)
log.debug("found bot user {0:s}".format(bot_user)) log.debug("found bot user %s", bot_user)
except BotUser.DoesNotExist: except BotUser.DoesNotExist:
log.debug("could not find bot user for {0:s}".format(source)) log.debug("could not find bot user for %s", source)
return False return False
try: try:
django_user = bot_user.user django_user = bot_user.user
if django_user.has_perm(permission): if django_user.has_perm(permission):
log.debug("bot user {0:s} has requested permission {1:s}".format(bot_user, permission)) log.debug("bot user %s has requested permission %s", bot_user, permission)
return True return True
except ObjectDoesNotExist: except ObjectDoesNotExist:
log.error("could not find django user for bot user {0:s}".format(bot_user)) log.error("could not find django user for bot user %s", bot_user)
return False return False
log.debug("bot user {0:s} does not have requested permission {1:s}".format(bot_user, permission)) log.debug("bot user %s does not have requested permission %s", bot_user, permission)
return False return False

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations
import django.utils.timezone import django.utils.timezone

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations
from django.conf import settings from django.conf import settings

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations
import ircbot.models import ircbot.models

View File

@ -1,7 +1,5 @@
"""Track basic IRC settings and similar.""" """Track basic IRC settings and similar."""
from __future__ import unicode_literals
import logging import logging
import re import re
@ -31,7 +29,7 @@ class Alias(models.Model):
class Meta: class Meta:
verbose_name_plural = "aliases" verbose_name_plural = "aliases"
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return "{0:s} -> {1:s}".format(self.pattern, self.replacement) return "{0:s} -> {1:s}".format(self.pattern, self.replacement)
@ -56,7 +54,7 @@ class BotUser(models.Model):
('quit_bot', "Can tell the bot to quit via IRC"), ('quit_bot', "Can tell the bot to quit via IRC"),
) )
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return "{0:s} (Django user {1:s})".format(self.nickmask, self.user.username) return "{0:s} (Django user {1:s})".format(self.nickmask, self.user.username)
@ -80,7 +78,7 @@ class IrcChannel(models.Model):
('manage_current_channels', "Can join/part channels via IRC"), ('manage_current_channels', "Can join/part channels via IRC"),
) )
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return "{0:s}".format(self.name) return "{0:s}".format(self.name)
@ -99,7 +97,7 @@ class IrcPlugin(models.Model):
('manage_loaded_plugins', "Can load/unload plugins via IRC"), ('manage_loaded_plugins', "Can load/unload plugins via IRC"),
) )
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return "{0:s}".format(self.path) return "{0:s}".format(self.path)

View File

@ -1,7 +1,5 @@
"""Karma hooks for the IRC bot.""" """Karma hooks for the IRC bot."""
from __future__ import unicode_literals
import logging import logging
import re import re
@ -63,7 +61,7 @@ class Karma(Plugin):
return return
# check the line for karma # check the line for karma
log.debug(u"searching '%s' for karma", what) log.debug("searching '%s' for karma", what)
matches = re.findall(karma_pattern, what, re.IGNORECASE) matches = re.findall(karma_pattern, what, re.IGNORECASE)
for match in matches: for match in matches:
key = match[0] if match[0] else match[1] key = match[0] if match[0] else match[1]

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,7 +1,5 @@
"""Karma logging models.""" """Karma logging models."""
from __future__ import unicode_literals
import logging import logging
import pytz import pytz
@ -35,7 +33,7 @@ class KarmaKey(models.Model):
objects = KarmaKeyManager() objects = KarmaKeyManager()
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return "{0:s} ({1:d})".format(self.key, self.score()) return "{0:s} ({1:d})".format(self.key, self.score())
@ -86,7 +84,7 @@ class KarmaLogEntry(models.Model):
class Meta: class Meta:
verbose_name_plural = 'karma log entries' verbose_name_plural = 'karma log entries'
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
tz = pytz.timezone(settings.TIME_ZONE) tz = pytz.timezone(settings.TIME_ZONE)

View File

@ -54,13 +54,13 @@ class Markov(Plugin):
line = match.group(6) line = match.group(6)
topics = [x for x in line.split(' ') if len(x) >= 3] topics = [x for x in line.split(' ') if len(x) >= 3]
return self.bot.reply(event, u" ".join(markovlib.generate_line(context, topics=topics, return self.bot.reply(event, " ".join(markovlib.generate_line(context, topics=topics,
min_words=min_size, max_words=max_size, min_words=min_size, max_words=max_size,
max_sentences=1))) max_sentences=1)))
else: else:
return self.bot.reply(event, u" ".join(markovlib.generate_line(context, min_words=min_size, return self.bot.reply(event, " ".join(markovlib.generate_line(context, min_words=min_size,
max_words=max_size, max_words=max_size,
max_sentences=1))) max_sentences=1)))
def handle_chatter(self, connection, event): def handle_chatter(self, connection, event):
"""Learn from IRC chatter.""" """Learn from IRC chatter."""
@ -82,11 +82,11 @@ class Markov(Plugin):
# learn the line # learn the line
recursing = getattr(event, '_recursing', False) recursing = getattr(event, '_recursing', False)
if not recursing: if not recursing:
log.debug(u"learning %s", trimmed_what) log.debug("learning %s", trimmed_what)
context = markovlib.get_or_create_target_context(target) context = markovlib.get_or_create_target_context(target)
markovlib.learn_line(trimmed_what, context) markovlib.learn_line(trimmed_what, context)
log.debug(u"searching '%s' for '%s'", what, my_nick) log.debug("searching '%s' for '%s'", what, my_nick)
if re.search(my_nick, what, re.IGNORECASE) is not None: if re.search(my_nick, what, re.IGNORECASE) is not None:
context = markovlib.get_or_create_target_context(target) context = markovlib.get_or_create_target_context(target)
@ -97,18 +97,18 @@ class Markov(Plugin):
# the speaker # the speaker
topics = [x for x in addressed_re.match(what).group(1).split(' ') if len(x) >= 3] topics = [x for x in addressed_re.match(what).group(1).split(' ') if len(x) >= 3]
return self.bot.reply(event, u"{0:s}: {1:s}" return self.bot.reply(event, "{0:s}: {1:s}"
u"".format(nick, u" ".join(markovlib.generate_line(context, "".format(nick, " ".join(markovlib.generate_line(context,
topics=topics, topics=topics,
max_sentences=1)))) max_sentences=1))))
else: else:
# i wasn't addressed directly, so just respond # i wasn't addressed directly, so just respond
topics = [x for x in what.split(' ') if len(x) >= 3] topics = [x for x in what.split(' ') if len(x) >= 3]
return self.bot.reply(event, u"{0:s}" return self.bot.reply(event, "{0:s}"
u"".format(u" ".join(markovlib.generate_line(context, "".format(" ".join(markovlib.generate_line(context,
topics=topics, topics=topics,
max_sentences=1)))) max_sentences=1))))
plugin = Markov plugin = Markov

View File

@ -55,14 +55,14 @@ def generate_sentence(context, topics=None, max_words=30):
if topics: if topics:
topic_word = random.choice(topics) topic_word = random.choice(topics)
topics.remove(topic_word) topics.remove(topic_word)
log.debug(u"looking for topic '{0:s}'".format(topic_word)) log.debug("looking for topic '{0:s}'".format(topic_word))
new_states = MarkovState.objects.filter(context=context, v=topic_word) new_states = MarkovState.objects.filter(context=context, v=topic_word)
if len(new_states) > 0: if len(new_states) > 0:
log.debug(u"found '{0:s}', starting backwards".format(topic_word)) log.debug("found '{0:s}', starting backwards".format(topic_word))
words.insert(0, topic_word) words.insert(0, topic_word)
while len(words) <= max_words and words[0] != MarkovState._start2: while len(words) <= max_words and words[0] != MarkovState._start2:
log.debug(u"looking backwards for '{0:s}'".format(words[0])) log.debug("looking backwards for '{0:s}'".format(words[0]))
new_states = MarkovState.objects.filter(context=context, v=words[0]) new_states = MarkovState.objects.filter(context=context, v=words[0])
words.insert(0, get_word_out_of_states(new_states, backwards=True)) words.insert(0, get_word_out_of_states(new_states, backwards=True))
@ -72,9 +72,9 @@ def generate_sentence(context, topics=None, max_words=30):
i = len(words) i = len(words)
while len(words) <= max_words and words[-1] != MarkovState._stop: while len(words) <= max_words and words[-1] != MarkovState._stop:
log.debug(u"looking for '{0:s}','{1:s}'".format(words[i-2], words[i-1])) log.debug("looking for '{0:s}','{1:s}'".format(words[i-2], words[i-1]))
new_states = MarkovState.objects.filter(context=context, k1=words[i-2], k2=words[i-1]) new_states = MarkovState.objects.filter(context=context, k1=words[i-2], k2=words[i-1])
log.debug(u"states retrieved") log.debug("states retrieved")
words.append(get_word_out_of_states(new_states)) words.append(get_word_out_of_states(new_states))
i += 1 i += 1
@ -119,7 +119,7 @@ def get_word_out_of_states(states, backwards=False):
count_sum = states.aggregate(Sum('count'))['count__sum'] count_sum = states.aggregate(Sum('count'))['count__sum']
hit = random.randint(0, count_sum) hit = random.randint(0, count_sum)
log.debug(u"sum: {0:d} hit: {1:d}".format(count_sum, hit)) log.debug("sum: {0:d} hit: {1:d}".format(count_sum, hit))
states_itr = states.iterator() states_itr = states.iterator()
for state in states_itr: for state in states_itr:
@ -132,14 +132,14 @@ def get_word_out_of_states(states, backwards=False):
break break
log.debug(u"found '{0:s}'".format(new_word)) log.debug("found '{0:s}'".format(new_word))
return new_word return new_word
def learn_line(line, context): def learn_line(line, context):
"""Create a bunch of MarkovStates for a given line of text.""" """Create a bunch of MarkovStates for a given line of text."""
log.debug(u"learning %s...", line[:40]) log.debug("learning %s...", line[:40])
words = line.split() words = line.split()
words = [MarkovState._start1, MarkovState._start2] + words + [MarkovState._stop] words = [MarkovState._start1, MarkovState._start2] + words + [MarkovState._stop]
@ -149,7 +149,7 @@ def learn_line(line, context):
return return
for i, word in enumerate(words): for i, word in enumerate(words):
log.debug(u"'{0:s}','{1:s}' -> '{2:s}'".format(words[i], words[i+1], words[i+2])) log.debug("'{0:s}','{1:s}' -> '{2:s}'".format(words[i], words[i+1], words[i+2]))
state, created = MarkovState.objects.get_or_create(context=context, state, created = MarkovState.objects.get_or_create(context=context,
k1=words[i], k1=words[i],
k2=words[i+1], k2=words[i+1],

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -17,10 +17,10 @@ class MarkovContext(models.Model):
name = models.CharField(max_length=200, unique=True) name = models.CharField(max_length=200, unique=True)
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return u"{0:s}".format(self.name) return "{0:s}".format(self.name)
class MarkovTarget(models.Model): class MarkovTarget(models.Model):
@ -32,10 +32,10 @@ class MarkovTarget(models.Model):
chatter_chance = models.IntegerField(default=0) chatter_chance = models.IntegerField(default=0)
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return u"{0:s} -> {1:s}".format(self.name, self.context.name) return "{0:s} -> {1:s}".format(self.name, self.context.name)
class MarkovState(models.Model): class MarkovState(models.Model):
@ -64,7 +64,7 @@ class MarkovState(models.Model):
} }
unique_together = ('context', 'k1', 'k2', 'v') unique_together = ('context', 'k1', 'k2', 'v')
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return u"{0:s},{1:s} -> {2:s} (count: {3:d})".format(self.k1, self.k2, self.v, self.count) return "{0:s},{1:s} -> {2:s} (count: {3:d})".format(self.k1, self.k2, self.v, self.count)

View File

@ -24,7 +24,7 @@ def context_index(request, context_id):
start_t = time.time() start_t = time.time()
context = get_object_or_404(MarkovContext, pk=context_id) context = get_object_or_404(MarkovContext, pk=context_id)
chain = u" ".join(markovlib.generate_line(context)) chain = " ".join(markovlib.generate_line(context))
end_t = time.time() end_t = time.time()
return render(request, 'context.html', {'chain': chain, return render(request, 'context.html', {'chain': chain,

View File

@ -1,5 +1,4 @@
# coding: utf-8 # coding: utf-8
from __future__ import unicode_literals
import logging import logging

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,7 +1,5 @@
"""Karma logging models.""" """Karma logging models."""
from __future__ import unicode_literals
import logging import logging
import math import math
import pytz import pytz
@ -56,7 +54,7 @@ class PiLog(models.Model):
class Meta: class Meta:
get_latest_by = 'created' get_latest_by = 'created'
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
tz = pytz.timezone(settings.TIME_ZONE) tz = pytz.timezone(settings.TIME_ZONE)

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations
import django.utils.timezone import django.utils.timezone

View File

@ -17,10 +17,10 @@ class Race(models.Model):
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
description = models.TextField() description = models.TextField()
def __unicode__(self): def __str__(self):
"""Text representation of a race.""" """Text representation of a race."""
return u"{0:s} ({1:s})".format(self.name, self.key) return "{0:s} ({1:s})".format(self.name, self.key)
class Racer(models.Model): class Racer(models.Model):
@ -37,10 +37,10 @@ class Racer(models.Model):
class Meta: class Meta:
unique_together = ('nick', 'race') unique_together = ('nick', 'race')
def __unicode__(self): def __str__(self):
"""Text representation of a race racer.""" """Text representation of a race racer."""
return u"{0:s} in {1:s}".format(self.nick, self.race.name) return "{0:s} in {1:s}".format(self.nick, self.race.name)
class RaceUpdate(models.Model): class RaceUpdate(models.Model):
@ -55,9 +55,9 @@ class RaceUpdate(models.Model):
class Meta: class Meta:
ordering = ['event_time',] ordering = ['event_time',]
def __unicode__(self): def __str__(self):
"""Text representation of a race update.""" """Text representation of a race update."""
local_time = timezone.localtime(self.event_time) local_time = timezone.localtime(self.event_time)
return u"{0:s} in {1:s} @ {2:s}".format(self.racer.nick, self.race.name, return "{0:s} in {1:s} @ {2:s}".format(self.racer.nick, self.race.name,
local_time.strftime('%Y-%m-%d %H:%M:%S %Z')) local_time.strftime('%Y-%m-%d %H:%M:%S %Z'))

View File

@ -4,7 +4,7 @@ from seen.models import SeenNick
class SeenNickAdmin(admin.ModelAdmin): class SeenNickAdmin(admin.ModelAdmin):
list_display = ('__unicode__', 'seen_time') list_display = ('__str__', 'seen_time')
admin.site.register(SeenNick, SeenNickAdmin) admin.site.register(SeenNick, SeenNickAdmin)

View File

@ -1,4 +1,4 @@
from __future__ import unicode_literals """Show seen chatter data over IRC."""
import logging import logging

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations
import django.utils.timezone import django.utils.timezone

View File

@ -17,9 +17,9 @@ class SeenNick(models.Model):
ordering = ['-seen_time',] ordering = ['-seen_time',]
unique_together = ('nick', 'channel') unique_together = ('nick', 'channel')
def __unicode__(self): def __str__(self):
"""String representation of a seen nick.""" """String representation of a seen nick."""
local_time = timezone.localtime(self.seen_time) local_time = timezone.localtime(self.seen_time)
return u"{0:s} seen in {1:s} at {2:s}".format(self.nick, self.channel, return "{0:s} seen in {1:s} at {2:s}".format(self.nick, self.channel,
local_time.strftime('%Y-%m-%d %H:%M:%S %Z')) local_time.strftime('%Y-%m-%d %H:%M:%S %Z'))

View File

@ -1,7 +1,5 @@
"""Collaborative nonsense story writing.""" """Collaborative nonsense story writing."""
from __future__ import unicode_literals
import logging import logging
import random import random
import re import re

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations
import datetime import datetime

View File

@ -1,7 +1,5 @@
"""Track storycraft games.""" """Track storycraft games."""
from __future__ import unicode_literals
import logging import logging
from django.db import models from django.db import models
@ -36,7 +34,7 @@ class StorycraftGame(models.Model):
start_time = models.DateTimeField(null=True) start_time = models.DateTimeField(null=True)
end_time = models.DateTimeField(null=True) end_time = models.DateTimeField(null=True)
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return "Storycraft game {0:d}: {1:s}; {2:s}".format(self.pk, self.summary(), self.get_progress_string()) return "Storycraft game {0:d}: {1:s}; {2:s}".format(self.pk, self.summary(), self.get_progress_string())
@ -95,7 +93,7 @@ class StorycraftPlayer(models.Model):
nick = models.CharField(max_length=64) nick = models.CharField(max_length=64)
nickmask = models.CharField(max_length=200) nickmask = models.CharField(max_length=200)
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return "{0:s} in storycraft game {1:d}".format(self.nick, self.game.pk) return "{0:s} in storycraft game {1:d}".format(self.nick, self.game.pk)
@ -110,7 +108,7 @@ class StorycraftLine(models.Model):
line = models.TextField(default="") line = models.TextField(default="")
time = models.DateTimeField(auto_now_add=True) time = models.DateTimeField(auto_now_add=True)
def __unicode__(self): def __str__(self):
"""String representation.""" """String representation."""
return "line by {0:s} in storycraft game {1:d}".format(self.player.nick, self.game.pk) return "line by {0:s} in storycraft game {1:d}".format(self.player.nick, self.game.pk)

View File

@ -1,8 +1,7 @@
"""Assorted text transformations (e.g. rot13).""" """Assorted text transformations (e.g. rot13)."""
from __future__ import unicode_literals
import base64 import base64
import codecs
from ircbot.lib import Plugin from ircbot.lib import Plugin
@ -42,7 +41,8 @@ class Transform(Plugin):
"""Apply a rot13 method to the text.""" """Apply a rot13 method to the text."""
text = match.group(1) text = match.group(1)
return self.bot.reply(event, text.encode('rot13', 'ignore')) encoder = codecs.getencoder('rot13')
return self.bot.reply(event, encoder(text)[0])
def handle_base64(self, connection, event, match): def handle_base64(self, connection, event, match):
"""Apply a base64 encoding to the text.""" """Apply a base64 encoding to the text."""
@ -51,9 +51,9 @@ class Transform(Plugin):
text = match.group(2) text = match.group(2)
if direction == 'encode': if direction == 'encode':
return self.bot.reply(event, base64.encodestring(text).replace('\n', '')) return self.bot.reply(event, base64.encodebytes(bytes(text, 'utf-8')).decode('utf-8'))
elif direction == 'decode': elif direction == 'decode':
return self.bot.reply(event, base64.decodestring(text).replace('\n', '')) return self.bot.reply(event, base64.decodebytes(bytes(text, 'utf-8')).decode('utf-8'))
def handle_upper(self, connection, event, match): def handle_upper(self, connection, event, match):
"""Uppercase the text.""" """Uppercase the text."""
@ -76,7 +76,7 @@ class Transform(Plugin):
cipher = {'A': 'Y', 'B': 'P', 'C': 'L', 'D': 'T', 'E': 'A', 'F': 'V', 'G': 'K', 'H': 'R', 'I': 'E', cipher = {'A': 'Y', 'B': 'P', 'C': 'L', 'D': 'T', 'E': 'A', 'F': 'V', 'G': 'K', 'H': 'R', 'I': 'E',
'J': 'Z', 'K': 'G', 'L': 'M', 'M': 'S', 'N': 'H', 'O': 'U', 'P': 'B', 'Q': 'X', 'R': 'N', 'J': 'Z', 'K': 'G', 'L': 'M', 'M': 'S', 'N': 'H', 'O': 'U', 'P': 'B', 'Q': 'X', 'R': 'N',
'S': 'C', 'T': 'D', 'U': 'I', 'V': 'J', 'W': 'F', 'X': 'Q', 'Y': 'O', 'Z': 'W'} 'S': 'C', 'T': 'D', 'U': 'I', 'V': 'J', 'W': 'F', 'X': 'Q', 'Y': 'O', 'Z': 'W'}
decipher = dict([(v, k) for (k, v) in cipher.iteritems()]) decipher = dict([(v, k) for (k, v) in list(cipher.items())])
if not reverse: if not reverse:
trans = [] trans = []

View File

@ -1,9 +1,6 @@
"""Access to Twitter through bot commands.""" """Access to Twitter through bot commands."""
from __future__ import unicode_literals
import logging import logging
import thread
import time import time
import requests import requests
@ -239,18 +236,18 @@ class Twitter(Plugin):
retweet = getattr(tweet, 'retweeted_status', None) retweet = getattr(tweet, 'retweeted_status', None)
if retweet: if retweet:
if print_source: if print_source:
reply = "@%s (RT @%s): %s" % (tweet['user']['screen_name'].encode('utf-8', 'ignore'), reply = "@%s (RT @%s): %s" % (tweet['user']['screen_name'],
retweet['user']['screen_name'].encode('utf-8', 'ignore'), retweet['user']['screen_name'],
self._unencode_xml(retweet['text'].encode('utf-8', 'ignore'))) self._unencode_xml(retweet['text']))
else: else:
reply = "(RT @%s): %s" % (retweet['user']['screen_name'].encode('utf-8', 'ignore'), reply = "(RT @%s): %s" % (retweet['user']['screen_name'],
self._unencode_xml(retweet['text'].encode('utf-8', 'ignore'))) self._unencode_xml(retweet['text']))
else: else:
if print_source: if print_source:
reply = "@%s: %s" % (tweet['user']['screen_name'].encode('utf-8', 'ignore'), reply = "@%s: %s" % (tweet['user']['screen_name'],
self._unencode_xml(tweet['text'].encode('utf-8', 'ignore'))) self._unencode_xml(tweet['text']))
else: else:
reply = "%s" % (self._unencode_xml(tweet['text'].encode('utf-8', 'ignore'))) reply = "%s" % (self._unencode_xml(tweet['text']))
if print_id: if print_id:
reply = reply + " [{0:d}]".format(tweet['id']) reply = reply + " [{0:d}]".format(tweet['id'])

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations

View File

@ -1,7 +1,5 @@
"""Twitter settings models.""" """Twitter settings models."""
from __future__ import unicode_literals
import logging import logging
from django.db import models from django.db import models

View File

@ -1,11 +1,8 @@
# coding: utf-8 # coding: utf-8
from __future__ import unicode_literals
import json
import logging import logging
import re import re
import urllib2 import requests
from django.conf import settings from django.conf import settings
@ -23,9 +20,9 @@ def get_conditions_for_query(queryitems):
try: try:
url = wu_base_url + ('{0:s}/q/{1:s}.json'.format('conditions', query)) url = wu_base_url + ('{0:s}/q/{1:s}.json'.format('conditions', query))
log.debug(u"calling %s", url) log.debug("calling %s", url)
json_resp = urllib2.urlopen(url) resp = requests.get(url)
condition_data = json.load(json_resp) condition_data = resp.json()
except IOError as e: except IOError as e:
log.error("error while making conditions query") log.error("error while making conditions query")
log.exception(e) log.exception(e)
@ -33,7 +30,7 @@ def get_conditions_for_query(queryitems):
# condition data is loaded. the rest of this is obviously specific to # condition data is loaded. the rest of this is obviously specific to
# http://www.wunderground.com/weather/api/d/docs?d=data/conditions # http://www.wunderground.com/weather/api/d/docs?d=data/conditions
log.debug(json.dumps(condition_data, sort_keys=True, indent=4)) log.debug(condition_data)
try: try:
# just see if we have current_observation data # just see if we have current_observation data
@ -137,8 +134,8 @@ def get_forecast_for_query(queryitems):
try: try:
url = wu_base_url + ('{0:s}/q/{1:s}.json'.format('forecast', query)) url = wu_base_url + ('{0:s}/q/{1:s}.json'.format('forecast', query))
json_resp = urllib2.urlopen(url) resp = requests.get(url)
forecast_data = json.load(json_resp) forecast_data = resp.json()
except IOError as e: except IOError as e:
log.error("error while making forecast query") log.error("error while making forecast query")
log.exception(e) log.exception(e)
@ -146,7 +143,7 @@ def get_forecast_for_query(queryitems):
# forecast data is loaded. the rest of this is obviously specific to # forecast data is loaded. the rest of this is obviously specific to
# http://www.wunderground.com/weather/api/d/docs?d=data/forecast # http://www.wunderground.com/weather/api/d/docs?d=data/forecast
log.debug(json.dumps(forecast_data, sort_keys=True, indent=4)) log.debug(forecast_data)
try: try:
# just see if we have forecast data # just see if we have forecast data

View File

@ -1,10 +1,14 @@
astroid==1.3.6 astroid==1.4.4
Django==1.8.4 caniusepython3==3.3.0
colorama==0.3.6
distlib==0.2.1
Django==1.8.8
django-adminplus==0.3 django-adminplus==0.3
django-extensions==1.5.3 django-extensions==1.5.3
django-filter==0.10.0 django-filter==0.10.0
djangorestframework==3.1.3 djangorestframework==3.1.3
dodgy==0.1.7 dodgy==0.1.7
futures==3.0.3
httplib2==0.7.4 httplib2==0.7.4
inflect==0.2.5 inflect==0.2.5
irc==12.1.4 irc==12.1.4
@ -16,33 +20,37 @@ jaraco.functools==1.3
jaraco.itertools==1.3 jaraco.itertools==1.3
jaraco.logging==1.2 jaraco.logging==1.2
jaraco.text==1.3 jaraco.text==1.3
jaraco.timing==1.2.2
lazy-object-proxy==1.2.1
logilab-astng==0.24.0 logilab-astng==0.24.0
logilab-common==0.63.2 logilab-common==0.63.2
Markdown==2.6.2 Markdown==2.6.5
mccabe==0.3.1 mccabe==0.3.1
more-itertools==2.2 more-itertools==2.2
oauth2==1.5.211 oauth2==1.9.0.post1
oauthlib==0.5.1 oauthlib==1.0.3
pep257==0.5.0 pep257==0.7.0
pep8==1.6.2 pep8==1.6.2
pep8-naming==0.2.2 pep8-naming==0.3.3
ply==3.4 ply==3.4
prospector==0.10.2 prospector==0.10.2
pyflakes==0.9.2 pyflakes==0.9.2
pylint==1.4.3 pylint==1.5.4
pylint-celery==0.3 pylint-celery==0.3
pylint-common==0.2.1 pylint-common==0.2.2
pylint-django==0.6.1 pylint-django==0.7.1
pylint-plugin-utils==0.2.3 pylint-plugin-utils==0.2.3
python-dateutil==2.1 python-dateutil==2.4.2
pytz==2015.4 pytz==2015.7
PyYAML==3.11 PyYAML==3.11
requests==1.2.3 requests==2.9.1
requests-oauthlib==0.3.2 requests-oauthlib==0.6.0
requirements-detector==0.4 requirements-detector==0.4.1
setoptconf==0.2.0 setoptconf==0.2.0
six==1.9.0 six==1.10.0
tempora==1.3 tempora==1.4
twython==3.0.0 twython==3.3.0
yg.lockfile==2.0 wheel==0.26.0
wrapt==1.10.6
yg.lockfile==2.1
zc.lockfile==1.1.0 zc.lockfile==1.1.0