Refactor to run in both Python 2.7 and Python 3.6

Refactor to run in both Python 2.7 and Python 3.6. This is important as
python 2.7 is end of life.

I tried to edit as few things as possible in this commit to minimize
conflicts which means the code could be prettier.

Signed-off-by: Viktor Sjölind <viktor@sjolind.se>
This commit is contained in:
Viktor Sjölind 2017-06-09 15:19:24 +02:00 committed by Jonatan Pålsson
parent 2125b2d739
commit 96e6da2752
5 changed files with 80 additions and 74 deletions

2
Db.py
View file

@ -57,4 +57,4 @@ def add_log_message(channel, nickname, message_type, message = None):
def show_all_messages(): def show_all_messages():
for message in LogMessage.select(): for message in LogMessage.select():
print "<%s> %s" % (message.nickname, message.message) print("<%s> %s" % (message.nickname, message.message))

View file

@ -25,7 +25,14 @@ write simpler bots.
""" """
import sys import sys
from UserDict import UserDict
# UserDict is moved to collections in Python3
# In order to support Python 2.7 this has to be imported
# in the following way
try:
from UserDict import UserDict
except ImportError:
from collections import UserDict
from irclib import SimpleIRCClient from irclib import SimpleIRCClient
from irclib import nm_to_n, irc_lower, all_events from irclib import nm_to_n, irc_lower, all_events
@ -160,7 +167,7 @@ class SingleServerIRCBot(SimpleIRCClient):
"""[Internal]""" """[Internal]"""
before = nm_to_n(e.source()) before = nm_to_n(e.source())
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)
@ -177,7 +184,7 @@ class SingleServerIRCBot(SimpleIRCClient):
def _on_quit(self, c, e): def _on_quit(self, c, e):
"""[Internal]""" """[Internal]"""
nick = nm_to_n(e.source()) nick = nm_to_n(e.source())
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)
@ -283,8 +290,6 @@ class IRCDict:
del self.canon_keys[ck] del self.canon_keys[ck]
def __iter__(self): def __iter__(self):
return iter(self.data) return iter(self.data)
def __contains__(self, key):
return self.has_key(key)
def clear(self): def clear(self):
self.data.clear() self.data.clear()
self.canon_keys.clear() self.canon_keys.clear()
@ -294,15 +299,15 @@ class IRCDict:
import copy import copy
return copy.copy(self) return copy.copy(self)
def keys(self): def keys(self):
return self.data.keys() return list(self.data.keys())
def items(self): def items(self):
return self.data.items() return list(self.data.items())
def values(self): def values(self):
return self.data.values() return list(self.data.values())
def has_key(self, key): def has_key(self, key):
return irc_lower(key) in self.canon_keys return irc_lower(key) in self.canon_keys
def update(self, dict): def update(self, dict):
for k, v in dict.items(): for k, v in list(dict.items()):
self.data[k] = v self.data[k] = v
def get(self, key, failobj=None): def get(self, key, failobj=None):
return self.data.get(key, failobj) return self.data.get(key, failobj)
@ -322,16 +327,16 @@ class Channel:
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 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

@ -207,8 +207,8 @@ class IRC:
incoming data, if there are any. If that seems boring, look incoming data, if there are any. If that seems boring, look
at the process_forever method. at the process_forever method.
""" """
sockets = map(lambda x: x._get_socket(), self.connections) sockets = [x._get_socket() for x in self.connections]
sockets = filter(lambda x: x != None, sockets) sockets = [x for x in sockets if x != None]
if sockets: if sockets:
(i, o, e) = select.select(sockets, [], [], timeout) (i, o, e) = select.select(sockets, [], [], timeout)
self.process_data(i) self.process_data(i)
@ -342,7 +342,7 @@ class Connection:
self.irclibobj = irclibobj self.irclibobj = irclibobj
def _get_socket(): def _get_socket():
raise IRCError, "Not overridden" raise IRCError("Not overridden")
############################## ##############################
### Convenience wrappers. ### Convenience wrappers.
@ -433,10 +433,10 @@ class ServerConnection(Connection):
self.socket.connect((self.server, self.port)) self.socket.connect((self.server, self.port))
if ssl: if ssl:
self.ssl = socket.ssl(self.socket) self.ssl = socket.ssl(self.socket)
except socket.error, x: except socket.error as x:
self.socket.close() self.socket.close()
self.socket = None self.socket = None
raise ServerConnectionError, "Couldn't connect to socket: %s" % x raise ServerConnectionError("Couldn't connect to socket: %s" % x)
self.connected = 1 self.connected = 1
if self.irclibobj.fn_to_add_socket: if self.irclibobj.fn_to_add_socket:
self.irclibobj.fn_to_add_socket(self.socket) self.irclibobj.fn_to_add_socket(self.socket)
@ -491,7 +491,7 @@ class ServerConnection(Connection):
new_data = self.ssl.read(2**14) new_data = self.ssl.read(2**14)
else: else:
new_data = self.socket.recv(2**14) new_data = self.socket.recv(2**14)
except socket.error, x: except socket.error as x:
# The server hung up. # The server hung up.
self.disconnect("Connection reset by peer") self.disconnect("Connection reset by peer")
return return
@ -500,14 +500,14 @@ class ServerConnection(Connection):
self.disconnect("Connection reset by peer") self.disconnect("Connection reset by peer")
return return
lines = _linesep_regexp.split(self.previous_buffer + new_data) lines = _linesep_regexp.split(self.previous_buffer + new_data.decode())
# Save the last, unfinished line. # Save the last, unfinished line.
self.previous_buffer = lines.pop() self.previous_buffer = lines.pop()
for line in lines: for line in lines:
if DEBUG: if DEBUG:
print "FROM SERVER:", line print("FROM SERVER:", line)
if not line: if not line:
continue continue
@ -561,7 +561,7 @@ class ServerConnection(Connection):
command = "privnotice" command = "privnotice"
for m in messages: for m in messages:
if type(m) is types.TupleType: if type(m) is tuple:
if command in ["privmsg", "pubmsg"]: if command in ["privmsg", "pubmsg"]:
command = "ctcp" command = "ctcp"
else: else:
@ -569,15 +569,15 @@ class ServerConnection(Connection):
m = list(m) m = list(m)
if DEBUG: if DEBUG:
print "command: %s, source: %s, target: %s, arguments: %s" % ( print("command: %s, source: %s, target: %s, arguments: %s" % (
command, prefix, target, m) command, prefix, target, m))
self._handle_event(Event(command, prefix, target, m)) self._handle_event(Event(command, prefix, target, m))
if command == "ctcp" and m[0] == "ACTION": if command == "ctcp" and m[0] == "ACTION":
self._handle_event(Event("action", prefix, target, m[1:])) self._handle_event(Event("action", prefix, target, m[1:]))
else: else:
if DEBUG: if DEBUG:
print "command: %s, source: %s, target: %s, arguments: %s" % ( print("command: %s, source: %s, target: %s, arguments: %s" % (
command, prefix, target, [m]) command, prefix, target, [m]))
self._handle_event(Event(command, prefix, target, [m])) self._handle_event(Event(command, prefix, target, [m]))
else: else:
target = None target = None
@ -595,8 +595,8 @@ class ServerConnection(Connection):
command = "umode" command = "umode"
if DEBUG: if DEBUG:
print "command: %s, source: %s, target: %s, arguments: %s" % ( print("command: %s, source: %s, target: %s, arguments: %s" % (
command, prefix, target, arguments) command, prefix, target, arguments))
self._handle_event(Event(command, prefix, target, arguments)) self._handle_event(Event(command, prefix, target, arguments))
def _handle_event(self, event): def _handle_event(self, event):
@ -660,7 +660,7 @@ class ServerConnection(Connection):
try: try:
self.socket.close() self.socket.close()
except socket.error, x: except socket.error as x:
pass pass
self.socket = None self.socket = None
self._handle_event(Event("disconnect", self.server, "", [message])) self._handle_event(Event("disconnect", self.server, "", [message]))
@ -743,7 +743,7 @@ class ServerConnection(Connection):
def part(self, channels, message=""): def part(self, channels, message=""):
"""Send a PART command.""" """Send a PART command."""
if type(channels) == types.StringType: if type(channels) == bytes:
self.send_raw("PART " + channels + (message and (" " + message))) self.send_raw("PART " + channels + (message and (" " + message)))
else: else:
self.send_raw("PART " + ",".join(channels) + (message and (" " + message))) self.send_raw("PART " + ",".join(channels) + (message and (" " + message)))
@ -782,15 +782,16 @@ class ServerConnection(Connection):
The string will be padded with appropriate CR LF. The string will be padded with appropriate CR LF.
""" """
if self.socket is None: if self.socket is None:
raise ServerNotConnectedError, "Not connected." raise ServerNotConnectedError("Not connected.")
try: try:
string += "\r\n"
if self.ssl: if self.ssl:
self.ssl.write(string + "\r\n") self.ssl.write(string.encode())
else: else:
self.socket.send(string + "\r\n") self.socket.send(string.encode())
if DEBUG: if DEBUG:
print "TO SERVER:", string print("TO SERVER:", string)
except socket.error, x: except socket.error as x:
# Ouch! # Ouch!
self.disconnect("Connection reset by peer.") self.disconnect("Connection reset by peer.")
@ -888,8 +889,8 @@ class DCCConnection(Connection):
self.passive = 0 self.passive = 0
try: try:
self.socket.connect((self.peeraddress, self.peerport)) self.socket.connect((self.peeraddress, self.peerport))
except socket.error, x: except socket.error as x:
raise DCCConnectionError, "Couldn't connect to socket: %s" % x raise DCCConnectionError("Couldn't connect to socket: %s" % x)
self.connected = 1 self.connected = 1
if self.irclibobj.fn_to_add_socket: if self.irclibobj.fn_to_add_socket:
self.irclibobj.fn_to_add_socket(self.socket) self.irclibobj.fn_to_add_socket(self.socket)
@ -913,8 +914,8 @@ class DCCConnection(Connection):
self.socket.bind((socket.gethostbyname(socket.gethostname()), 0)) self.socket.bind((socket.gethostbyname(socket.gethostname()), 0))
self.localaddress, self.localport = self.socket.getsockname() self.localaddress, self.localport = self.socket.getsockname()
self.socket.listen(10) self.socket.listen(10)
except socket.error, x: except socket.error as x:
raise DCCConnectionError, "Couldn't bind socket: %s" % x raise DCCConnectionError("Couldn't bind socket: %s" % x)
return self return self
def disconnect(self, message=""): def disconnect(self, message=""):
@ -930,7 +931,7 @@ class DCCConnection(Connection):
self.connected = 0 self.connected = 0
try: try:
self.socket.close() self.socket.close()
except socket.error, x: except socket.error as x:
pass pass
self.socket = None self.socket = None
self.irclibobj._handle_event( self.irclibobj._handle_event(
@ -947,8 +948,8 @@ class DCCConnection(Connection):
self.socket = conn self.socket = conn
self.connected = 1 self.connected = 1
if DEBUG: if DEBUG:
print "DCC connection from %s:%d" % ( print("DCC connection from %s:%d" % (
self.peeraddress, self.peerport) self.peeraddress, self.peerport))
self.irclibobj._handle_event( self.irclibobj._handle_event(
self, self,
Event("dcc_connect", self.peeraddress, None, None)) Event("dcc_connect", self.peeraddress, None, None))
@ -956,7 +957,7 @@ class DCCConnection(Connection):
try: try:
new_data = self.socket.recv(2**14) new_data = self.socket.recv(2**14)
except socket.error, x: except socket.error as x:
# The server hung up. # The server hung up.
self.disconnect("Connection reset by peer") self.disconnect("Connection reset by peer")
return return
@ -985,11 +986,11 @@ class DCCConnection(Connection):
target = None target = None
for chunk in chunks: for chunk in chunks:
if DEBUG: if DEBUG:
print "FROM PEER:", chunk print("FROM PEER:", chunk)
arguments = [chunk] arguments = [chunk]
if DEBUG: if DEBUG:
print "command: %s, source: %s, target: %s, arguments: %s" % ( print("command: %s, source: %s, target: %s, arguments: %s" % (
command, prefix, target, arguments) command, prefix, target, arguments))
self.irclibobj._handle_event( self.irclibobj._handle_event(
self, self,
Event(command, prefix, target, arguments)) Event(command, prefix, target, arguments))
@ -1009,8 +1010,8 @@ class DCCConnection(Connection):
if self.dcctype == "chat": if self.dcctype == "chat":
self.socket.send("\n") self.socket.send("\n")
if DEBUG: if DEBUG:
print "TO PEER: %s\n" % string print("TO PEER: %s\n" % string)
except socket.error, x: except socket.error as x:
# Ouch! # Ouch!
self.disconnect("Connection reset by peer.") self.disconnect("Connection reset by peer.")
@ -1181,10 +1182,6 @@ def mask_matches(nick, mask):
r = re.compile(mask, re.IGNORECASE) r = re.compile(mask, re.IGNORECASE)
return r.match(nick) return r.match(nick)
_special = "-[]\\`^{}"
nick_characters = string.ascii_letters + string.digits + _special
_ircstring_translation = string.maketrans(string.ascii_uppercase + "[]\\^",
string.ascii_lowercase + "{}|~")
def irc_lower(s): def irc_lower(s):
"""Returns a lowercased string. """Returns a lowercased string.
@ -1192,7 +1189,12 @@ def irc_lower(s):
The definition of lowercased comes from the IRC specification (RFC The definition of lowercased comes from the IRC specification (RFC
1459). 1459).
""" """
return s.translate(_ircstring_translation) s = s.lower()
s = s.replace("[", "{")
s = s.replace("]", "}")
s = s.replace("\\", "|")
s = s.replace("^", "~")
return s
def _ctcp_dequote(message): def _ctcp_dequote(message):
"""[Internal] Dequote a message according to CTCP specifications. """[Internal] Dequote a message according to CTCP specifications.
@ -1259,16 +1261,16 @@ def ip_numstr_to_quad(num):
"""Convert an IP number as an integer given in ASCII """Convert an IP number as an integer given in ASCII
representation (e.g. '3232235521') to an IP address string representation (e.g. '3232235521') to an IP address string
(e.g. '192.168.0.1').""" (e.g. '192.168.0.1')."""
n = long(num) n = int(num)
p = map(str, map(int, [n >> 24 & 0xFF, n >> 16 & 0xFF, p = list(map(str, list(map(int, [n >> 24 & 0xFF, n >> 16 & 0xFF,
n >> 8 & 0xFF, n & 0xFF])) n >> 8 & 0xFF, n & 0xFF]))))
return ".".join(p) return ".".join(p)
def ip_quad_to_numstr(quad): def ip_quad_to_numstr(quad):
"""Convert an IP address string (e.g. '192.168.0.1') to an IP """Convert an IP address string (e.g. '192.168.0.1') to an IP
number as an integer given in ASCII representation number as an integer given in ASCII representation
(e.g. '3232235521').""" (e.g. '3232235521')."""
p = map(long, quad.split(".")) p = list(map(int, quad.split(".")))
s = str((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]) s = str((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
if s[-1] == "L": if s[-1] == "L":
s = s[:-1] s = s[:-1]
@ -1557,4 +1559,4 @@ protocol_events = [
"pong", "pong",
] ]
all_events = generated_events + protocol_events + numeric_events.values() all_events = generated_events + protocol_events + list(numeric_events.values())

View file

@ -164,18 +164,17 @@ def channels():
def append_line(filename, line): def append_line(filename, line):
data = open(filename, "rb").readlines()[:-2] data = open(filename, "rb").readlines()[:-2]
data += [line, "\n", "\n</body>", "\n</html>"] data += [line.encode(), "\n".encode(), "\n</body>".encode(), "\n</html>".encode()]
write_lines(filename, data) write_lines(filename, data)
def write_lines(filename, lines): def write_lines(filename, lines):
f = open(filename, "wb") with open(filename, "wb") as f:
f.writelines(lines) f.writelines(lines)
f.close()
def write_string(filename, string): def write_string(filename, string):
f = open(filename, "wb") with open(filename, "wb") as f:
f.write(string) f.write(string.encode())
f.close()
color_pattern = re.compile(r'(\[\d{1,2}m)') color_pattern = re.compile(r'(\[\d{1,2}m)')
"Pattern that matches ANSI color codes and the text that follows" "Pattern that matches ANSI color codes and the text that follows"
@ -205,15 +204,15 @@ class Logbot(SingleServerIRCBot):
self.set_ftp() self.set_ftp()
self.nick_pass = nick_pass self.nick_pass = nick_pass
print "Logbot %s" % __version__ print("Logbot %s" % __version__)
print "Connecting to %s:%i..." % (server, port) print("Connecting to %s:%i..." % (server, port))
print "Press Ctrl-C to quit" print("Press Ctrl-C to quit")
def quit(self): def quit(self):
self.connection.disconnect("Quitting...") self.connection.disconnect("Quitting...")
def color(self, user): def color(self, user):
return "#%s" % md5(user).hexdigest()[:6] return "#%s" % md5(user.encode()).hexdigest()[:6]
def set_ftp(self, ftp=None): def set_ftp(self, ftp=None):
self.ftp = ftp self.ftp = ftp
@ -257,7 +256,7 @@ class Logbot(SingleServerIRCBot):
def on_all_raw_messages(self, c, e): def on_all_raw_messages(self, c, e):
"""Display all IRC connections in terminal""" """Display all IRC connections in terminal"""
if DEBUG: print e.arguments()[0] if DEBUG: print(e.arguments()[0])
def on_welcome(self, c, e): def on_welcome(self, c, e):
"""Join channels after successful connection""" """Join channels after successful connection"""
@ -327,7 +326,7 @@ class Logbot(SingleServerIRCBot):
def on_privmsg(self, c, e): def on_privmsg(self, c, e):
# c.privmsg(nm_to_n(e.source()), self.format["help"]) # c.privmsg(nm_to_n(e.source()), self.format["help"])
pas pass
def on_quit(self, c, e): def on_quit(self, c, e):
nick = nm_to_n(e.source()) nick = nm_to_n(e.source())
@ -340,7 +339,7 @@ class Logbot(SingleServerIRCBot):
self.write_event("topic", e) self.write_event("topic", e)
def connect_ftp(): def connect_ftp():
print "Using FTP %s..." % (FTP_SERVER) print("Using FTP %s..." % (FTP_SERVER))
f = ftplib.FTP(FTP_SERVER, FTP_USER, FTP_PASS) f = ftplib.FTP(FTP_SERVER, FTP_USER, FTP_PASS)
f.cwd(FTP_FOLDER) f.cwd(FTP_FOLDER)
return f return f

View file

@ -69,7 +69,7 @@ class PullRequest:
for repo in self.repos: for repo in self.repos:
r = requests.get(repo["uri"]) r = requests.get(repo["uri"])
if r.status_code != 200: if r.status_code != 200:
print "Error fetching %s", repo["name"] print("Error fetching %s", repo["name"])
break break
prs = r.json() prs = r.json()
@ -83,4 +83,4 @@ class PullRequest:
if __name__ == "__main__": if __name__ == "__main__":
p = PullRequest() p = PullRequest()
for line in p.check_all(): for line in p.check_all():
print line["message"] print(line["message"])