Add python3 compatibility.

This commit is contained in:
poljar (Damir Jelić) 2018-01-23 13:30:42 +01:00
parent c2e9662180
commit f6e72c09c6

View file

@ -9,9 +9,10 @@ import time
import datetime import datetime
import pprint import pprint
import re import re
import sys
# pylint: disable=redefined-builtin # pylint: disable=redefined-builtin
from builtins import bytes from builtins import bytes, str
from collections import deque, Mapping, Iterable, namedtuple from collections import deque, Mapping, Iterable, namedtuple
from operator import itemgetter from operator import itemgetter
@ -26,27 +27,27 @@ from http_parser.pyparser import HttpParser
# pylint: disable=import-error # pylint: disable=import-error
import weechat import weechat
WEECHAT_SCRIPT_NAME = "matrix" # type: unicode WEECHAT_SCRIPT_NAME = "matrix" # type: str
WEECHAT_SCRIPT_DESCRIPTION = "matrix chat plugin" # type: unicode WEECHAT_SCRIPT_DESCRIPTION = "matrix chat plugin" # type: str
WEECHAT_SCRIPT_AUTHOR = "Damir Jelić <poljar@termina.org.uk>" # type: unicode WEECHAT_SCRIPT_AUTHOR = "Damir Jelić <poljar@termina.org.uk>" # type: str
WEECHAT_SCRIPT_VERSION = "0.1" # type: unicode WEECHAT_SCRIPT_VERSION = "0.1" # type: str
WEECHAT_SCRIPT_LICENSE = "MIT" # type: unicode WEECHAT_SCRIPT_LICENSE = "MIT" # type: str
MATRIX_API_PATH = "/_matrix/client/r0" # type: unicode MATRIX_API_PATH = "/_matrix/client/r0" # type: str
SERVERS = dict() # type: Dict[unicode, MatrixServer] SERVERS = dict() # type: Dict[str, MatrixServer]
CONFIG = None # type: weechat.config CONFIG = None # type: weechat.config
GLOBAL_OPTIONS = None # type: PluginOptions GLOBAL_OPTIONS = None # type: PluginOptions
# Unicode handling # Unicode handling
def encode_to_utf8(data): def encode_to_utf8(data):
if isinstance(data, unicode): if isinstance(data, str):
return data.encode('utf-8') return data.encode('utf-8')
if isinstance(data, bytes): if isinstance(data, bytes):
return data return data
elif isinstance(data, Mapping): elif isinstance(data, Mapping):
return type(data)(map(encode_to_utf8, data.iteritems())) return type(data)(map(encode_to_utf8, data.items()))
elif isinstance(data, Iterable): elif isinstance(data, Iterable):
return type(data)(map(encode_to_utf8, data)) return type(data)(map(encode_to_utf8, data))
return data return data
@ -55,10 +56,10 @@ def encode_to_utf8(data):
def decode_from_utf8(data): def decode_from_utf8(data):
if isinstance(data, bytes): if isinstance(data, bytes):
return data.decode('utf-8') return data.decode('utf-8')
if isinstance(data, unicode): if isinstance(data, str):
return data return data
elif isinstance(data, Mapping): elif isinstance(data, Mapping):
return type(data)(map(decode_from_utf8, data.iteritems())) return type(data)(map(decode_from_utf8, data.items()))
elif isinstance(data, Iterable): elif isinstance(data, Iterable):
return type(data)(map(decode_from_utf8, data)) return type(data)(map(decode_from_utf8, data))
return data return data
@ -165,13 +166,13 @@ class PluginOptions:
self.redaction_comp_len = 50 # type: int self.redaction_comp_len = 50 # type: int
self.options = dict() # type: Dict[unicode, weechat.config_option] self.options = dict() # type: Dict[str, weechat.config_option]
class HttpResponse: class HttpResponse:
def __init__(self, status, headers, body): def __init__(self, status, headers, body):
self.status = status # type: int self.status = status # type: int
self.headers = headers # type: Dict[unicode, unicode] self.headers = headers # type: Dict[str, str]
self.body = body # type: bytes self.body = body # type: bytes
@ -179,22 +180,22 @@ class HttpRequest:
def __init__( def __init__(
self, self,
request_type, # type: RequestType request_type, # type: RequestType
host, # type: unicode host, # type: str
port, # type: int port, # type: int
location, # type: unicode location, # type: str
data=None, # type: Dict[unicode, Any] data=None, # type: Dict[str, Any]
user_agent='weechat-matrix/{version}'.format( user_agent='weechat-matrix/{version}'.format(
version=WEECHAT_SCRIPT_VERSION) # type: unicode version=WEECHAT_SCRIPT_VERSION) # type: str
): ):
# type: (...) -> None # type: (...) -> None
host_string = ':'.join([host, str(port)]) host_string = ':'.join([host, str(port)])
user_agent = 'User-Agent: {agent}'.format(agent=user_agent) user_agent = 'User-Agent: {agent}'.format(agent=user_agent)
host_header = 'Host: {host}'.format(host=host_string) host_header = 'Host: {host}'.format(host=host_string)
request_list = [] # type: List[unicode] request_list = [] # type: List[str]
accept_header = 'Accept: */*' # type: unicode accept_header = 'Accept: */*' # type: str
end_separator = '\r\n' # type: unicode end_separator = '\r\n' # type: str
payload = None # type: unicode payload = None # type: str
if request_type == RequestType.GET: if request_type == RequestType.GET:
get = 'GET {location} HTTP/1.1'.format(location=location) get = 'GET {location} HTTP/1.1'.format(location=location)
@ -244,16 +245,16 @@ class MatrixMessage:
self, self,
server, # type: MatrixServer server, # type: MatrixServer
message_type, # type: MessageType message_type, # type: MessageType
room_id=None, # type: unicode room_id=None, # type: str
extra_id=None, # type: unicode extra_id=None, # type: str
data=None, # type: Dict[unicode, Any] data=None, # type: Dict[str, Any]
extra_data=None # type: Dict[unicode, Any] extra_data=None # type: Dict[str, Any]
): ):
# type: (...) -> None # type: (...) -> None
self.type = message_type # MessageType self.type = message_type # MessageType
self.request = None # HttpRequest self.request = None # HttpRequest
self.response = None # HttpResponse self.response = None # HttpResponse
self.extra_data = extra_data # Dict[unicode, Any] self.extra_data = extra_data # Dict[str, Any]
if message_type == MessageType.LOGIN: if message_type == MessageType.LOGIN:
path = ("{api}/login").format(api=MATRIX_API_PATH) path = ("{api}/login").format(api=MATRIX_API_PATH)
@ -358,34 +359,34 @@ class MatrixMessage:
class MatrixUser: class MatrixUser:
def __init__(self, name, display_name): def __init__(self, name, display_name):
self.name = name # type: unicode self.name = name # type: str
self.display_name = display_name # type: unicode self.display_name = display_name # type: str
self.power_level = 0 # type: int self.power_level = 0 # type: int
self.nick_color = "" # type: unicode self.nick_color = "" # type: str
self.prefix = "" # type: unicode self.prefix = "" # type: str
class MatrixRoom: class MatrixRoom:
def __init__(self, room_id): def __init__(self, room_id):
# type: (unicode) -> None # type: (str) -> None
self.room_id = room_id # type: unicode self.room_id = room_id # type: str
self.alias = room_id # type: unicode self.alias = room_id # type: str
self.topic = "" # type: unicode self.topic = "" # type: str
self.topic_author = "" # type: unicode self.topic_author = "" # type: str
self.topic_date = None # type: datetime.datetime self.topic_date = None # type: datetime.datetime
self.prev_batch = "" # type: unicode self.prev_batch = "" # type: str
self.users = dict() # type: Dict[unicode, MatrixUser] self.users = dict() # type: Dict[str, MatrixUser]
self.encrypted = False # type: bool self.encrypted = False # type: bool
def key_from_value(dictionary, value): def key_from_value(dictionary, value):
# type: (Dict[unicode, Any], Any) -> unicode # type: (Dict[str, Any], Any) -> str
return list(dictionary.keys())[list(dictionary.values()).index(value)] return list(dictionary.keys())[list(dictionary.values()).index(value)]
@utf8_decode @utf8_decode
def server_config_change_cb(server_name, option): def server_config_change_cb(server_name, option):
# type: (unicode, weechat.config_option) -> int # type: (str, weechat.config_option) -> int
server = SERVERS[server_name] server = SERVERS[server_name]
option_name = None option_name = None
@ -428,22 +429,22 @@ def server_config_change_cb(server_name, option):
class MatrixServer: class MatrixServer:
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
def __init__(self, name, config_file): def __init__(self, name, config_file):
# type: (unicode, weechat.config) -> None # type: (str, weechat.config) -> None
self.name = name # type: unicode self.name = name # type: str
self.user_id = "" self.user_id = ""
self.address = "" # type: unicode self.address = "" # type: str
self.port = 8448 # type: int self.port = 8448 # type: int
self.options = dict() # type: Dict[unicode, weechat.config] self.options = dict() # type: Dict[str, weechat.config]
self.user = "" # type: unicode self.user = "" # type: str
self.password = "" # type: unicode self.password = "" # type: str
self.rooms = dict() # type: Dict[unicode, MatrixRoom] self.rooms = dict() # type: Dict[str, MatrixRoom]
self.buffers = dict() # type: Dict[unicode, weechat.buffer] self.buffers = dict() # type: Dict[str, weechat.buffer]
self.server_buffer = None # type: weechat.buffer self.server_buffer = None # type: weechat.buffer
self.fd_hook = None # type: weechat.hook self.fd_hook = None # type: weechat.hook
self.timer_hook = None # type: weechat.hook self.timer_hook = None # type: weechat.hook
self.numeric_address = "" # type: unicode self.numeric_address = "" # type: str
self.autoconnect = False # type: bool self.autoconnect = False # type: bool
self.connected = False # type: bool self.connected = False # type: bool
@ -452,8 +453,8 @@ class MatrixServer:
self.socket = None # type: ssl.SSLSocket self.socket = None # type: ssl.SSLSocket
self.ssl_context = ssl.create_default_context() # type: ssl.SSLContext self.ssl_context = ssl.create_default_context() # type: ssl.SSLContext
self.access_token = None # type: unicode self.access_token = None # type: str
self.next_batch = None # type: unicode self.next_batch = None # type: str
self.transaction_id = 0 # type: int self.transaction_id = 0 # type: int
self.http_parser = HttpParser() # type: HttpParser self.http_parser = HttpParser() # type: HttpParser
@ -464,7 +465,7 @@ class MatrixServer:
# Queue of messages we send off and are waiting a response for # Queue of messages we send off and are waiting a response for
self.receive_queue = deque() # type: Deque[MatrixMessage] self.receive_queue = deque() # type: Deque[MatrixMessage]
self.message_queue = deque() # type: Deque[MatrixMessage] self.message_queue = deque() # type: Deque[MatrixMessage]
self.ignore_event_list = [] # type: List[unicode] self.ignore_event_list = [] # type: List[str]
self._create_options(config_file) self._create_options(config_file)
@ -528,8 +529,8 @@ def wrap_socket(server, file_descriptor):
# For python 2.7 wrap_socket() doesn't work with sockets created from an # For python 2.7 wrap_socket() doesn't work with sockets created from an
# file descriptor because fromfd() doesn't return a wrapped socket, the bug # file descriptor because fromfd() doesn't return a wrapped socket, the bug
# was fixed for python 3, more info https://bugs.python.org/issue13942 # was fixed for python 3, more info https://bugs.python.org/issue13942
# pylint: disable=protected-access # pylint: disable=protected-access,unidiomatic-typecheck
if isinstance(temp_socket, socket._socket.socket): if type(temp_socket) == socket._socket.socket:
# pylint: disable=no-member # pylint: disable=no-member
sock = socket._socketobject(_sock=temp_socket) sock = socket._socketobject(_sock=temp_socket)
else: else:
@ -557,11 +558,11 @@ def handle_http_response(server, message):
def decode_json(server, json_string): def decode_json(server, json_string):
try: try:
return json.loads(json_string, encoding='utf-8') return json.loads(json_string, encoding='utf-8')
except Exception as e: except Exception as error:
message = ("{prefix}matrix: Error decoding json response from " message = ("{prefix}matrix: Error decoding json response from "
"server: {error}").format( "server: {error}").format(
prefix=W.prefix("error"), prefix=W.prefix("error"),
error=e) error=error)
W.prnt(server.server_buffer, message) W.prnt(server.server_buffer, message)
return None return None
@ -633,7 +634,7 @@ def handle_http_response(server, message):
def strip_matrix_server(string): def strip_matrix_server(string):
# type: (unicode) -> unicode # type: (str) -> str
return string.rsplit(":", 1)[0] return string.rsplit(":", 1)[0]
@ -661,7 +662,7 @@ def add_user_to_nicklist(buf, user):
def matrix_create_room_buffer(server, room_id): def matrix_create_room_buffer(server, room_id):
# type: (MatrixServer, unicode) -> None # type: (MatrixServer, str) -> None
buf = W.buffer_new( buf = W.buffer_new(
room_id, room_id,
"room_input_cb", "room_input_cb",
@ -695,7 +696,7 @@ def matrix_create_room_buffer(server, room_id):
def matrix_handle_room_aliases(server, room_id, event): def matrix_handle_room_aliases(server, room_id, event):
# type: (MatrixServer, unicode, Dict[unicode, Any]) -> None # type: (MatrixServer, str, Dict[str, Any]) -> None
buf = server.buffers[room_id] buf = server.buffers[room_id]
room = server.rooms[room_id] room = server.rooms[room_id]
@ -713,7 +714,7 @@ def matrix_handle_room_aliases(server, room_id, event):
def matrix_handle_room_members(server, room_id, event): def matrix_handle_room_members(server, room_id, event):
# type: (MatrixServer, unicode, Dict[unicode, Any]) -> None # type: (MatrixServer, str, Dict[str, Any]) -> None
buf = server.buffers[room_id] buf = server.buffers[room_id]
room = server.rooms[room_id] room = server.rooms[room_id]
@ -773,7 +774,7 @@ def color_for_tags(color):
def matrix_handle_room_text_message(server, room_id, event, old=False): def matrix_handle_room_text_message(server, room_id, event, old=False):
# type: (MatrixServer, unicode, Dict[unicode, Any], bool) -> None # type: (MatrixServer, str, Dict[str, Any], bool) -> None
tag = "" tag = ""
msg_author = "" msg_author = ""
nick_color_name = "" nick_color_name = ""
@ -815,7 +816,7 @@ def matrix_handle_room_text_message(server, room_id, event, old=False):
def matrix_handle_redacted_message(server, room_id, event): def matrix_handle_redacted_message(server, room_id, event):
# type: (MatrixServer, unicode, Dict[Any, Any]) -> None # type: (MatrixServer, str, Dict[Any, Any]) -> None
reason = "" reason = ""
room = server.rooms[room_id] room = server.rooms[room_id]
@ -875,7 +876,7 @@ def matrix_handle_redacted_message(server, room_id, event):
def matrix_handle_room_messages(server, room_id, event, old=False): def matrix_handle_room_messages(server, room_id, event, old=False):
# type: (MatrixServer, unicode, Dict[unicode, Any], bool) -> None # type: (MatrixServer, str, Dict[str, Any], bool) -> None
if event['type'] == 'm.room.message': if event['type'] == 'm.room.message':
if 'redacted_by' in event['unsigned']: if 'redacted_by' in event['unsigned']:
matrix_handle_redacted_message(server, room_id, event) matrix_handle_redacted_message(server, room_id, event)
@ -894,7 +895,7 @@ def matrix_handle_room_messages(server, room_id, event, old=False):
def event_id_from_tags(tags): def event_id_from_tags(tags):
# type: (List[unicode]) -> unicode # type: (List[str]) -> str
for tag in tags: for tag in tags:
if tag.startswith("matrix_id"): if tag.startswith("matrix_id"):
return tag[10:] return tag[10:]
@ -976,7 +977,7 @@ def matrix_handle_room_redaction(server, room_id, event):
def get_prefix_for_level(level): def get_prefix_for_level(level):
# type: (int) -> unicode # type: (int) -> str
if level >= 100: if level >= 100:
return "&" return "&"
elif level >= 50: elif level >= 50:
@ -988,7 +989,7 @@ def get_prefix_for_level(level):
# TODO make this configurable # TODO make this configurable
def get_prefix_color(prefix): def get_prefix_color(prefix):
# type: (unicode) -> unicode # type: (str) -> str
if prefix == "&": if prefix == "&":
return "lightgreen" return "lightgreen"
elif prefix == "@": elif prefix == "@":
@ -1019,7 +1020,7 @@ def matrix_handle_room_power_levels(server, room_id, event):
def matrix_handle_room_events(server, room_id, room_events): def matrix_handle_room_events(server, room_id, room_events):
# type: (MatrixServer, unicode, Dict[Any, Any]) -> None # type: (MatrixServer, str, Dict[Any, Any]) -> None
for event in room_events: for event in room_events:
if event['event_id'] in server.ignore_event_list: if event['event_id'] in server.ignore_event_list:
server.ignore_event_list.remove(event['event_id']) server.ignore_event_list.remove(event['event_id'])
@ -1131,7 +1132,7 @@ def matrix_handle_room_events(server, room_id, room_events):
def matrix_handle_room_info(server, room_info): def matrix_handle_room_info(server, room_info):
# type: (MatrixServer, Dict) -> None # type: (MatrixServer, Dict) -> None
for room_id, room in room_info['join'].iteritems(): for room_id, room in room_info['join'].items():
if not room_id: if not room_id:
continue continue
@ -1191,7 +1192,7 @@ def matrix_sort_old_messages(server, room_id):
# will reverse the list at the same time # will reverse the list at the same time
while sorted_lines: while sorted_lines:
line = sorted_lines.pop() line = sorted_lines.pop()
new_line = {k: unicode(v) for k, v in line.items()} new_line = {k: str(v) for k, v in line.items()}
lines.append(new_line) lines.append(new_line)
matrix_update_buffer_lines(lines, own_lines) matrix_update_buffer_lines(lines, own_lines)
@ -1230,8 +1231,8 @@ def matrix_handle_old_messages(server, room_id, events):
def matrix_handle_message( def matrix_handle_message(
server, # type: MatrixServer server, # type: MatrixServer
message_type, # type: MessageType message_type, # type: MessageType
response, # type: Dict[unicode, Any] response, # type: Dict[str, Any]
extra_data # type: Dict[unicode, Any] extra_data # type: Dict[str, Any]
): ):
# type: (...) -> None # type: (...) -> None
@ -1410,7 +1411,7 @@ def disconnect(server):
def server_buffer_prnt(server, string): def server_buffer_prnt(server, string):
# type: (MatrixServer, unicode) -> None # type: (MatrixServer, str) -> None
assert server.server_buffer assert server.server_buffer
buffer = server.server_buffer buffer = server.server_buffer
now = int(time.time()) now = int(time.time())
@ -1562,7 +1563,7 @@ def reconnect_cb(server_name, remaining):
def connect(server): def connect(server):
# type: (MatrixServer) -> bool # type: (MatrixServer) -> int
if not server.address or not server.port: if not server.address or not server.port:
message = "{prefix}Server address or port not set".format( message = "{prefix}Server address or port not set".format(
prefix=W.prefix("error")) prefix=W.prefix("error"))
@ -2489,7 +2490,7 @@ def matrix_command_pgup_cb(data, buffer, command):
def tags_from_line_data(line_data): def tags_from_line_data(line_data):
# type: (weechat.hdata) -> List[unicode] # type: (weechat.hdata) -> List[str]
tags_count = W.hdata_get_var_array_size( tags_count = W.hdata_get_var_array_size(
W.hdata_get('line_data'), W.hdata_get('line_data'),
line_data, line_data,
@ -2506,7 +2507,7 @@ def tags_from_line_data(line_data):
def event_id_from_line(buf, target_number): def event_id_from_line(buf, target_number):
# type: (weechat.buffer, int) -> unicode # type: (weechat.buffer, int) -> str
own_lines = W.hdata_pointer(W.hdata_get('buffer'), buf, 'own_lines') own_lines = W.hdata_pointer(W.hdata_get('buffer'), buf, 'own_lines')
if own_lines: if own_lines:
line = W.hdata_pointer( line = W.hdata_pointer(
@ -2660,6 +2661,7 @@ def hook_page_up():
@utf8_decode @utf8_decode
def matrix_bar_item_plugin(data, item, window, buffer, extra_info): def matrix_bar_item_plugin(data, item, window, buffer, extra_info):
# pylint: disable=unused-argument
for server in SERVERS.values(): for server in SERVERS.values():
if (buffer in server.buffers.values() or if (buffer in server.buffers.values() or
buffer == server.server_buffer): buffer == server.server_buffer):
@ -2673,6 +2675,7 @@ def matrix_bar_item_plugin(data, item, window, buffer, extra_info):
@utf8_decode @utf8_decode
def matrix_bar_item_name(data, item, window, buffer, extra_info): def matrix_bar_item_name(data, item, window, buffer, extra_info):
# pylint: disable=unused-argument
for server in SERVERS.values(): for server in SERVERS.values():
if buffer in server.buffers.values(): if buffer in server.buffers.values():
color = ("status_name_ssl" color = ("status_name_ssl"
@ -2797,7 +2800,7 @@ def autoconnect(servers):
if __name__ == "__main__": if __name__ == "__main__":
W = WeechatWrapper(weechat) W = weechat if sys.hexversion >= 0x3000000 else WeechatWrapper(weechat)
if W.register(WEECHAT_SCRIPT_NAME, if W.register(WEECHAT_SCRIPT_NAME,
WEECHAT_SCRIPT_AUTHOR, WEECHAT_SCRIPT_AUTHOR,