From 96e6da275246ff0c5ea17756c6335790a033d890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Sj=C3=B6lind?= Date: Fri, 9 Jun 2017 15:19:24 +0200 Subject: [PATCH] Refactor to run in both Python 2.7 and Python 3.6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- Db.py | 2 +- ircbot.py | 29 +++++++++------- irclib.py | 92 ++++++++++++++++++++++++++------------------------ logbot.py | 27 +++++++-------- pullrequest.py | 4 +-- 5 files changed, 80 insertions(+), 74 deletions(-) diff --git a/Db.py b/Db.py index 7e30ca0..802bf0c 100644 --- a/Db.py +++ b/Db.py @@ -57,4 +57,4 @@ def add_log_message(channel, nickname, message_type, message = None): def show_all_messages(): for message in LogMessage.select(): - print "<%s> %s" % (message.nickname, message.message) + print("<%s> %s" % (message.nickname, message.message)) diff --git a/ircbot.py b/ircbot.py index 6f29a65..9cf6c1f 100644 --- a/ircbot.py +++ b/ircbot.py @@ -25,7 +25,14 @@ write simpler bots. """ 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 nm_to_n, irc_lower, all_events @@ -160,7 +167,7 @@ class SingleServerIRCBot(SimpleIRCClient): """[Internal]""" before = nm_to_n(e.source()) 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) @@ -177,7 +184,7 @@ class SingleServerIRCBot(SimpleIRCClient): def _on_quit(self, c, e): """[Internal]""" nick = nm_to_n(e.source()) - for ch in self.channels.values(): + for ch in list(self.channels.values()): if ch.has_user(nick): ch.remove_user(nick) @@ -283,8 +290,6 @@ class IRCDict: del self.canon_keys[ck] def __iter__(self): return iter(self.data) - def __contains__(self, key): - return self.has_key(key) def clear(self): self.data.clear() self.canon_keys.clear() @@ -294,15 +299,15 @@ class IRCDict: import copy return copy.copy(self) def keys(self): - return self.data.keys() + return list(self.data.keys()) def items(self): - return self.data.items() + return list(self.data.items()) def values(self): - return self.data.values() + return list(self.data.values()) def has_key(self, key): return irc_lower(key) in self.canon_keys def update(self, dict): - for k, v in dict.items(): + for k, v in list(dict.items()): self.data[k] = v def get(self, key, failobj=None): return self.data.get(key, failobj) @@ -322,16 +327,16 @@ class Channel: 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 has_user(self, nick): """Check whether the channel has a user.""" diff --git a/irclib.py b/irclib.py index 5f7141c..3499298 100644 --- a/irclib.py +++ b/irclib.py @@ -207,8 +207,8 @@ class IRC: incoming data, if there are any. If that seems boring, look at the process_forever method. """ - sockets = map(lambda x: x._get_socket(), self.connections) - sockets = filter(lambda x: x != None, sockets) + sockets = [x._get_socket() for x in self.connections] + sockets = [x for x in sockets if x != None] if sockets: (i, o, e) = select.select(sockets, [], [], timeout) self.process_data(i) @@ -342,7 +342,7 @@ class Connection: self.irclibobj = irclibobj def _get_socket(): - raise IRCError, "Not overridden" + raise IRCError("Not overridden") ############################## ### Convenience wrappers. @@ -433,10 +433,10 @@ class ServerConnection(Connection): self.socket.connect((self.server, self.port)) if ssl: self.ssl = socket.ssl(self.socket) - except socket.error, x: + except socket.error as x: self.socket.close() self.socket = None - raise ServerConnectionError, "Couldn't connect to socket: %s" % x + raise ServerConnectionError("Couldn't connect to socket: %s" % x) self.connected = 1 if self.irclibobj.fn_to_add_socket: self.irclibobj.fn_to_add_socket(self.socket) @@ -491,7 +491,7 @@ class ServerConnection(Connection): new_data = self.ssl.read(2**14) else: new_data = self.socket.recv(2**14) - except socket.error, x: + except socket.error as x: # The server hung up. self.disconnect("Connection reset by peer") return @@ -500,14 +500,14 @@ class ServerConnection(Connection): self.disconnect("Connection reset by peer") 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. self.previous_buffer = lines.pop() for line in lines: if DEBUG: - print "FROM SERVER:", line + print("FROM SERVER:", line) if not line: continue @@ -561,7 +561,7 @@ class ServerConnection(Connection): command = "privnotice" for m in messages: - if type(m) is types.TupleType: + if type(m) is tuple: if command in ["privmsg", "pubmsg"]: command = "ctcp" else: @@ -569,15 +569,15 @@ class ServerConnection(Connection): m = list(m) if DEBUG: - print "command: %s, source: %s, target: %s, arguments: %s" % ( - command, prefix, target, m) + print("command: %s, source: %s, target: %s, arguments: %s" % ( + command, prefix, target, m)) self._handle_event(Event(command, prefix, target, m)) if command == "ctcp" and m[0] == "ACTION": self._handle_event(Event("action", prefix, target, m[1:])) else: if DEBUG: - print "command: %s, source: %s, target: %s, arguments: %s" % ( - command, prefix, target, [m]) + print("command: %s, source: %s, target: %s, arguments: %s" % ( + command, prefix, target, [m])) self._handle_event(Event(command, prefix, target, [m])) else: target = None @@ -595,8 +595,8 @@ class ServerConnection(Connection): command = "umode" if DEBUG: - print "command: %s, source: %s, target: %s, arguments: %s" % ( - command, prefix, target, arguments) + print("command: %s, source: %s, target: %s, arguments: %s" % ( + command, prefix, target, arguments)) self._handle_event(Event(command, prefix, target, arguments)) def _handle_event(self, event): @@ -660,7 +660,7 @@ class ServerConnection(Connection): try: self.socket.close() - except socket.error, x: + except socket.error as x: pass self.socket = None self._handle_event(Event("disconnect", self.server, "", [message])) @@ -743,7 +743,7 @@ class ServerConnection(Connection): def part(self, channels, message=""): """Send a PART command.""" - if type(channels) == types.StringType: + if type(channels) == bytes: self.send_raw("PART " + channels + (message and (" " + message))) else: 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. """ if self.socket is None: - raise ServerNotConnectedError, "Not connected." + raise ServerNotConnectedError("Not connected.") try: + string += "\r\n" if self.ssl: - self.ssl.write(string + "\r\n") + self.ssl.write(string.encode()) else: - self.socket.send(string + "\r\n") + self.socket.send(string.encode()) if DEBUG: - print "TO SERVER:", string - except socket.error, x: + print("TO SERVER:", string) + except socket.error as x: # Ouch! self.disconnect("Connection reset by peer.") @@ -888,8 +889,8 @@ class DCCConnection(Connection): self.passive = 0 try: self.socket.connect((self.peeraddress, self.peerport)) - except socket.error, x: - raise DCCConnectionError, "Couldn't connect to socket: %s" % x + except socket.error as x: + raise DCCConnectionError("Couldn't connect to socket: %s" % x) self.connected = 1 if self.irclibobj.fn_to_add_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.localaddress, self.localport = self.socket.getsockname() self.socket.listen(10) - except socket.error, x: - raise DCCConnectionError, "Couldn't bind socket: %s" % x + except socket.error as x: + raise DCCConnectionError("Couldn't bind socket: %s" % x) return self def disconnect(self, message=""): @@ -930,7 +931,7 @@ class DCCConnection(Connection): self.connected = 0 try: self.socket.close() - except socket.error, x: + except socket.error as x: pass self.socket = None self.irclibobj._handle_event( @@ -947,8 +948,8 @@ class DCCConnection(Connection): self.socket = conn self.connected = 1 if DEBUG: - print "DCC connection from %s:%d" % ( - self.peeraddress, self.peerport) + print("DCC connection from %s:%d" % ( + self.peeraddress, self.peerport)) self.irclibobj._handle_event( self, Event("dcc_connect", self.peeraddress, None, None)) @@ -956,7 +957,7 @@ class DCCConnection(Connection): try: new_data = self.socket.recv(2**14) - except socket.error, x: + except socket.error as x: # The server hung up. self.disconnect("Connection reset by peer") return @@ -985,11 +986,11 @@ class DCCConnection(Connection): target = None for chunk in chunks: if DEBUG: - print "FROM PEER:", chunk + print("FROM PEER:", chunk) arguments = [chunk] if DEBUG: - print "command: %s, source: %s, target: %s, arguments: %s" % ( - command, prefix, target, arguments) + print("command: %s, source: %s, target: %s, arguments: %s" % ( + command, prefix, target, arguments)) self.irclibobj._handle_event( self, Event(command, prefix, target, arguments)) @@ -1009,8 +1010,8 @@ class DCCConnection(Connection): if self.dcctype == "chat": self.socket.send("\n") if DEBUG: - print "TO PEER: %s\n" % string - except socket.error, x: + print("TO PEER: %s\n" % string) + except socket.error as x: # Ouch! self.disconnect("Connection reset by peer.") @@ -1181,10 +1182,6 @@ def mask_matches(nick, mask): r = re.compile(mask, re.IGNORECASE) 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): """Returns a lowercased string. @@ -1192,7 +1189,12 @@ def irc_lower(s): The definition of lowercased comes from the IRC specification (RFC 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): """[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 representation (e.g. '3232235521') to an IP address string (e.g. '192.168.0.1').""" - n = long(num) - p = map(str, map(int, [n >> 24 & 0xFF, n >> 16 & 0xFF, - n >> 8 & 0xFF, n & 0xFF])) + n = int(num) + p = list(map(str, list(map(int, [n >> 24 & 0xFF, n >> 16 & 0xFF, + n >> 8 & 0xFF, n & 0xFF])))) return ".".join(p) def ip_quad_to_numstr(quad): """Convert an IP address string (e.g. '192.168.0.1') to an IP number as an integer given in ASCII representation (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]) if s[-1] == "L": s = s[:-1] @@ -1557,4 +1559,4 @@ protocol_events = [ "pong", ] -all_events = generated_events + protocol_events + numeric_events.values() +all_events = generated_events + protocol_events + list(numeric_events.values()) diff --git a/logbot.py b/logbot.py index 2b84199..be0964c 100755 --- a/logbot.py +++ b/logbot.py @@ -164,18 +164,17 @@ def channels(): def append_line(filename, line): data = open(filename, "rb").readlines()[:-2] - data += [line, "\n", "\n", "\n"] + data += [line.encode(), "\n".encode(), "\n".encode(), "\n".encode()] write_lines(filename, data) def write_lines(filename, lines): - f = open(filename, "wb") - f.writelines(lines) - f.close() + with open(filename, "wb") as f: + f.writelines(lines) + def write_string(filename, string): - f = open(filename, "wb") - f.write(string) - f.close() + with open(filename, "wb") as f: + f.write(string.encode()) color_pattern = re.compile(r'(\[\d{1,2}m)') "Pattern that matches ANSI color codes and the text that follows" @@ -205,15 +204,15 @@ class Logbot(SingleServerIRCBot): self.set_ftp() self.nick_pass = nick_pass - print "Logbot %s" % __version__ - print "Connecting to %s:%i..." % (server, port) - print "Press Ctrl-C to quit" + print("Logbot %s" % __version__) + print("Connecting to %s:%i..." % (server, port)) + print("Press Ctrl-C to quit") def quit(self): self.connection.disconnect("Quitting...") def color(self, user): - return "#%s" % md5(user).hexdigest()[:6] + return "#%s" % md5(user.encode()).hexdigest()[:6] def set_ftp(self, ftp=None): self.ftp = ftp @@ -257,7 +256,7 @@ class Logbot(SingleServerIRCBot): def on_all_raw_messages(self, c, e): """Display all IRC connections in terminal""" - if DEBUG: print e.arguments()[0] + if DEBUG: print(e.arguments()[0]) def on_welcome(self, c, e): """Join channels after successful connection""" @@ -327,7 +326,7 @@ class Logbot(SingleServerIRCBot): def on_privmsg(self, c, e): # c.privmsg(nm_to_n(e.source()), self.format["help"]) - pas + pass def on_quit(self, c, e): nick = nm_to_n(e.source()) @@ -340,7 +339,7 @@ class Logbot(SingleServerIRCBot): self.write_event("topic", e) 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.cwd(FTP_FOLDER) return f diff --git a/pullrequest.py b/pullrequest.py index 3d003a9..8fac4ab 100644 --- a/pullrequest.py +++ b/pullrequest.py @@ -69,7 +69,7 @@ class PullRequest: for repo in self.repos: r = requests.get(repo["uri"]) if r.status_code != 200: - print "Error fetching %s", repo["name"] + print("Error fetching %s", repo["name"]) break prs = r.json() @@ -83,4 +83,4 @@ class PullRequest: if __name__ == "__main__": p = PullRequest() for line in p.check_all(): - print line["message"] + print(line["message"])