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 random
import thread
import threading
import time
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}'. "
"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
def _generate_acro():
@ -254,12 +256,14 @@ class Acro(Plugin):
"""Begin the voting period."""
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)
self.bot.privmsg(self.game.channel, "here are the results. vote with !acro vote [number]")
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):
"""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."""
i = 0
for s in self.game.rounds[-1].submissions.keys():
votes = filter(lambda x: x == s, self.game.rounds[-1].votes.values())
for s in list(self.game.rounds[-1].submissions.keys()):
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)))
i += 1
def _add_round_scores_to_game_scores(self):
"""Apply the final round scores to the totall scores for the game."""
for s in self.game.rounds[-1].votes.values():
votes = filter(lambda x: x == s, self.game.rounds[-1].votes.values())
if s in self.game.scores.keys():
for s in list(self.game.rounds[-1].votes.values()):
votes = [x for x in list(self.game.rounds[-1].votes.values()) if x == s]
if s in list(self.game.scores.keys()):
self.game.scores[s] += len(votes)
else:
self.game.scores[s] = len(votes)
@ -338,7 +342,7 @@ class Acro(Plugin):
def _print_game_scores(self):
"""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]))

View File

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

View File

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

View File

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

View File

@ -1,7 +1,5 @@
"""Countdown item models."""
from __future__ import unicode_literals
import logging
from django.db import models
@ -20,7 +18,7 @@ class CountdownItem(models.Model):
created_time = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
def __str__(self):
"""String representation."""
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.
"""
a = range(dice)
a = list(range(dice))
for i in range(dice):
a[i] = random.randint(1, size)
if keep != dice:

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,5 @@
"""Track dispatcher configurations."""
from __future__ import unicode_literals
import logging
from django.db import models
@ -21,7 +19,7 @@ class Dispatcher(models.Model):
('send_message', "Can send messages to dispatchers"),
)
def __unicode__(self):
def __str__(self):
"""String representation."""
return "{0:s}".format(self.key)
@ -44,7 +42,7 @@ class DispatcherAction(models.Model):
destination = models.CharField(max_length=200)
include_key = models.BooleanField(default=False)
def __unicode__(self):
def __str__(self):
"""String representation."""
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."""
from __future__ import unicode_literals
import copy
import logging
import os
import xmlrpclib
import xmlrpc.client
from django.conf import settings
from rest_framework import generics, status
@ -79,7 +77,7 @@ class DispatchMessage(generics.GenericAPIView):
# connect over XML-RPC and send
try:
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)
bot.privmsg(action.destination, text)
except Exception as e:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,5 @@
"""Store "facts"."""
from __future__ import unicode_literals
import logging
import random
@ -21,7 +19,7 @@ class FactCategory(models.Model):
class Meta:
verbose_name_plural = 'fact categories'
def __unicode__(self):
def __str__(self):
"""String representation."""
return "{0:s}".format(self.name)
@ -60,7 +58,7 @@ class Fact(models.Model):
objects = FactManager()
def __unicode__(self):
def __str__(self):
"""String representation."""
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."""
from __future__ import unicode_literals
import logging
import xmlrpclib
import xmlrpc.client
from django.conf import settings
from django.contrib import admin
@ -32,7 +30,7 @@ def send_privmsg(request):
message = form.cleaned_data['message']
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)
form = PrivmsgForm()
else:

View File

@ -1,17 +1,15 @@
"""Provide the base IRC client bot which other code can latch onto."""
from __future__ import unicode_literals
import bisect
import collections
import copy
import logging
import re
from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
import socket
import ssl
import sys
import thread
import threading
import time
from django.conf import settings
@ -106,7 +104,7 @@ class DrReactor(irc.client.Reactor):
handler = PrioritizedRegexHandler(priority, regex, handler)
for event in events:
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, [])
bisect.insort(event_regex_handlers, handler)
@ -149,7 +147,7 @@ class DrReactor(irc.client.Reactor):
# only do aliasing for pubmsg/privmsg
if event.type in ['pubmsg', 'privmsg']:
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():
repl = alias.replace(what)
@ -161,18 +159,18 @@ class DrReactor(irc.client.Reactor):
with self.mutex:
# 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(
self.regex_handlers.get("all_events", []) +
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:
log.debug(u"checking %s vs. %s", handler, event.arguments)
log.debug("checking %s vs. %s", handler, event.arguments)
for line in event.arguments:
match = re.search(handler.regex, line)
if match:
log.debug(u"match!")
log.debug("match!")
result = handler.callback(connection, event, match)
if result == "NO MORE":
return
@ -182,7 +180,7 @@ class DrReactor(irc.client.Reactor):
self.handlers.get(event.type, [])
)
for handler in matching_handlers:
log.debug(u"not-match")
log.debug("not-match")
result = handler.callback(connection, event)
if result == "NO MORE":
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)
try:
# begin recursion search
attempt = event.arguments[0]
log.debug(u"checking it against %s", attempt)
log.debug("checking it against %s", attempt)
start_idx = attempt.find('[')
subcmd = attempt[start_idx+1:]
@ -219,7 +217,7 @@ class DrReactor(irc.client.Reactor):
subcmd = subcmd[:end_idx]
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
# 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._recursing = True
log.debug(u"new event copied")
log.debug("new event copied")
self.try_recursion(connection, newevent)
@ -243,7 +241,7 @@ class DrReactor(irc.client.Reactor):
# event's [] section with it.
oldtext = event.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
# 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
# last search on the text.
else:
log.debug(u"no more recursion here")
log.debug("no more recursion here")
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):
"""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
if event.type in ['pubmsg', 'privmsg']:
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():
repl = alias.replace(what)
@ -282,22 +280,22 @@ class DrReactor(irc.client.Reactor):
with self.mutex:
# 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(
self.regex_handlers.get("all_events", []) +
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:
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:
match = re.search(handler.regex, line)
if match:
log.debug(u"match (recursion)!")
log.debug("match (recursion)!")
result = handler.callback(connection, event, match)
log.debug(u"result: %s", result)
log.debug("result: %s", result)
if result:
log.debug(u"appending %s to replies", result)
log.debug("appending %s to replies", result)
replies.append(result)
matching_handlers = sorted(
@ -305,11 +303,11 @@ class DrReactor(irc.client.Reactor):
self.handlers.get(event.type, [])
)
for handler in matching_handlers:
log.debug(u"not-match (recursion)")
log.debug("not-match (recursion)")
result = handler.callback(connection, event)
log.debug(u"result: %s", result)
log.debug("result: %s", result)
if result:
log.debug(u"appending %s to replies", result)
log.debug("appending %s to replies", result)
replies.append(result)
if len(replies):
@ -364,7 +362,9 @@ class IRCBot(irc.client.SimpleIRCClient):
requestHandler=IrcBotXMLRPCRequestHandler, allow_none=True)
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
self.xmlrpc.register_function(self.privmsg, 'privmsg')
@ -457,7 +457,7 @@ class IRCBot(irc.client.SimpleIRCClient):
def _on_nick(self, c, e):
before = e.source.nick
after = e.target
for ch in self.channels.values():
for ch in list(self.channels.values()):
if ch.has_user(before):
ch.change_nick(before, after)
@ -472,7 +472,7 @@ class IRCBot(irc.client.SimpleIRCClient):
def _on_quit(self, c, e):
nick = e.source.nick
for ch in self.channels.values():
for ch in list(self.channels.values()):
if ch.has_user(nick):
ch.remove_user(nick)
@ -501,11 +501,11 @@ class IRCBot(irc.client.SimpleIRCClient):
time.sleep(settings.IRCBOT_SLEEP_BEFORE_AUTOJOIN_SECONDS)
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)
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)
match = re.search(r'(\S+!\S+@\S+)', what)
@ -579,10 +579,10 @@ class IRCBot(irc.client.SimpleIRCClient):
"""Handle IRC requests to load a plugin."""
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:
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)
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.
"""
log.debug(u"trying to load %s", plugin_path)
log.debug("trying to load %s", plugin_path)
dest = None
if feedback:
@ -621,28 +621,28 @@ class IRCBot(irc.client.SimpleIRCClient):
log.exception(e)
# i don't think this would get populated if __import__ failed del sys.modules[plugin_path]
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:
log.error("Error loading '{0:s}'".format(plugin_path))
log.exception(e)
del sys.modules[plugin_path]
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):
"""Handle IRC requests to unload a plugin."""
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:
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)
def _unload_plugin(self, connection, event, plugin_path):
"""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)
@ -722,9 +722,9 @@ class IRCBot(irc.client.SimpleIRCClient):
"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)
log.debug(u"replypath: %s", replypath)
log.debug("replypath: %s", replypath)
if replystr is not None:
recursing = getattr(event, '_recursing', False)
@ -773,9 +773,9 @@ class IRCBot(irc.client.SimpleIRCClient):
def sigint_handler(self, signal, frame):
"""Cleanly shutdown on SIGINT."""
log.debug(u"shutting down")
log.debug("shutting down")
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))
plugin.stop()
del plugin
@ -798,28 +798,28 @@ class Channel(object):
def users(self):
"""Returns an unsorted list of the channel's users."""
return self.userdict.keys()
return list(self.userdict.keys())
def opers(self):
"""Returns an unsorted list of the channel's operators."""
return self.operdict.keys()
return list(self.operdict.keys())
def voiced(self):
"""Returns an unsorted list of the persons that have voice
mode set in the channel."""
return self.voiceddict.keys()
return list(self.voiceddict.keys())
def owners(self):
"""Returns an unsorted list of the channel's owners."""
return self.ownerdict.keys()
return list(self.ownerdict.keys())
def halfops(self):
"""Returns an unsorted list of the channel's half-operators."""
return self.halfopdict.keys()
return list(self.halfopdict.keys())
def has_user(self, nick):
"""Check whether the channel has a user."""

View File

@ -39,7 +39,7 @@ class ChannelManagement(Plugin):
channel = match.group(1)
# put it in the database if it isn't already
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)
return self.bot.reply(event, "Joined channel {0:s}.".format(channel))
@ -51,7 +51,7 @@ class ChannelManagement(Plugin):
channel = match.group(1)
# put it in the database if it isn't already
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)
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

View File

@ -1,7 +1,5 @@
"""Library and convenience methods for the IRC bot and plugins."""
from __future__ import unicode_literals
import logging
import irc.client
@ -25,17 +23,17 @@ class Plugin(object):
self.connection = connection
self.event = event
log.info(u"initialized %s", self.__class__.__name__)
log.info("initialized %s", self.__class__.__name__)
def start(self):
"""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):
"""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):
"""Convert <, >, & to their real entities."""
@ -51,21 +49,21 @@ def has_permission(source, permission):
try:
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:
log.debug("could not find bot user for {0:s}".format(source))
log.debug("could not find bot user for %s", source)
return False
try:
django_user = bot_user.user
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
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
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,5 @@
"""Track basic IRC settings and similar."""
from __future__ import unicode_literals
import logging
import re
@ -31,7 +29,7 @@ class Alias(models.Model):
class Meta:
verbose_name_plural = "aliases"
def __unicode__(self):
def __str__(self):
"""String representation."""
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"),
)
def __unicode__(self):
def __str__(self):
"""String representation."""
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"),
)
def __unicode__(self):
def __str__(self):
"""String representation."""
return "{0:s}".format(self.name)
@ -99,7 +97,7 @@ class IrcPlugin(models.Model):
('manage_loaded_plugins', "Can load/unload plugins via IRC"),
)
def __unicode__(self):
def __str__(self):
"""String representation."""
return "{0:s}".format(self.path)

View File

@ -1,7 +1,5 @@
"""Karma hooks for the IRC bot."""
from __future__ import unicode_literals
import logging
import re
@ -63,7 +61,7 @@ class Karma(Plugin):
return
# 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)
for match in matches:
key = match[0] if match[0] else match[1]

View File

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

View File

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

View File

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

View File

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

View File

@ -55,14 +55,14 @@ def generate_sentence(context, topics=None, max_words=30):
if topics:
topic_word = random.choice(topics)
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)
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)
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])
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)
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])
log.debug(u"states retrieved")
log.debug("states retrieved")
words.append(get_word_out_of_states(new_states))
i += 1
@ -119,7 +119,7 @@ def get_word_out_of_states(states, backwards=False):
count_sum = states.aggregate(Sum('count'))['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()
for state in states_itr:
@ -132,14 +132,14 @@ def get_word_out_of_states(states, backwards=False):
break
log.debug(u"found '{0:s}'".format(new_word))
log.debug("found '{0:s}'".format(new_word))
return new_word
def learn_line(line, context):
"""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 = [MarkovState._start1, MarkovState._start2] + words + [MarkovState._stop]
@ -149,7 +149,7 @@ def learn_line(line, context):
return
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,
k1=words[i],
k2=words[i+1],

View File

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

View File

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

View File

@ -17,10 +17,10 @@ class MarkovContext(models.Model):
name = models.CharField(max_length=200, unique=True)
def __unicode__(self):
def __str__(self):
"""String representation."""
return u"{0:s}".format(self.name)
return "{0:s}".format(self.name)
class MarkovTarget(models.Model):
@ -32,10 +32,10 @@ class MarkovTarget(models.Model):
chatter_chance = models.IntegerField(default=0)
def __unicode__(self):
def __str__(self):
"""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):
@ -64,7 +64,7 @@ class MarkovState(models.Model):
}
unique_together = ('context', 'k1', 'k2', 'v')
def __unicode__(self):
def __str__(self):
"""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()
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()
return render(request, 'context.html', {'chain': chain,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,5 @@
"""Track storycraft games."""
from __future__ import unicode_literals
import logging
from django.db import models
@ -36,7 +34,7 @@ class StorycraftGame(models.Model):
start_time = models.DateTimeField(null=True)
end_time = models.DateTimeField(null=True)
def __unicode__(self):
def __str__(self):
"""String representation."""
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)
nickmask = models.CharField(max_length=200)
def __unicode__(self):
def __str__(self):
"""String representation."""
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="")
time = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
def __str__(self):
"""String representation."""
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)."""
from __future__ import unicode_literals
import base64
import codecs
from ircbot.lib import Plugin
@ -42,7 +41,8 @@ class Transform(Plugin):
"""Apply a rot13 method to the text."""
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):
"""Apply a base64 encoding to the text."""
@ -51,9 +51,9 @@ class Transform(Plugin):
text = match.group(2)
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':
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):
"""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',
'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'}
decipher = dict([(v, k) for (k, v) in cipher.iteritems()])
decipher = dict([(v, k) for (k, v) in list(cipher.items())])
if not reverse:
trans = []

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,11 +1,8 @@
# coding: utf-8
from __future__ import unicode_literals
import json
import logging
import re
import urllib2
import requests
from django.conf import settings
@ -23,9 +20,9 @@ def get_conditions_for_query(queryitems):
try:
url = wu_base_url + ('{0:s}/q/{1:s}.json'.format('conditions', query))
log.debug(u"calling %s", url)
json_resp = urllib2.urlopen(url)
condition_data = json.load(json_resp)
log.debug("calling %s", url)
resp = requests.get(url)
condition_data = resp.json()
except IOError as e:
log.error("error while making conditions query")
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
# 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:
# just see if we have current_observation data
@ -137,8 +134,8 @@ def get_forecast_for_query(queryitems):
try:
url = wu_base_url + ('{0:s}/q/{1:s}.json'.format('forecast', query))
json_resp = urllib2.urlopen(url)
forecast_data = json.load(json_resp)
resp = requests.get(url)
forecast_data = resp.json()
except IOError as e:
log.error("error while making forecast query")
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
# 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:
# just see if we have forecast data

View File

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