diff --git a/.travis.yml b/.travis.yml index 03f3e81..ebaca86 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,9 @@ language: python python: - - "2.7" + - "3.7" + - "3.8" + - "3.9" install: - pip install flake8 diff --git a/README.adoc b/README.adoc index c3378b0..074dc3d 100644 --- a/README.adoc +++ b/README.adoc @@ -25,13 +25,13 @@ Following packages are *required*: * WeeChat (version >= 0.3.7) on local or remote machine, with relay plugin enabled and listening on a port with protocol "weechat" -* Python 2.x >= 2.6 -* PySide (recommended, packages: python.pyside.*) or PyQt4 (python-qt4) +* Python 3.7+ +* PySide6 === Install via source distribution ---- -$ python setup.py install +$ pip install . ---- == WeeChat setup diff --git a/qweechat/about.py b/qweechat/about.py index b5c397e..88dd027 100644 --- a/qweechat/about.py +++ b/qweechat/about.py @@ -20,10 +20,8 @@ # along with QWeeChat. If not, see . # -import qt_compat - -QtCore = qt_compat.import_module('QtCore') -QtGui = qt_compat.import_module('QtGui') +from PySide6 import QtCore +from PySide6 import QtWidgets as QtGui class AboutDialog(QtGui.QDialog): @@ -44,7 +42,7 @@ class AboutDialog(QtGui.QDialog): vbox = QtGui.QVBoxLayout() for msg in messages: - label = QtGui.QLabel(msg.decode('utf-8')) + label = QtGui.QLabel(msg) label.setAlignment(QtCore.Qt.AlignHCenter) vbox.addWidget(label) vbox.addLayout(hbox) diff --git a/qweechat/buffer.py b/qweechat/buffer.py index 81aa4b7..4320fdd 100644 --- a/qweechat/buffer.py +++ b/qweechat/buffer.py @@ -19,22 +19,20 @@ # You should have received a copy of the GNU General Public License # along with QWeeChat. If not, see . # - from pkg_resources import resource_filename -import qt_compat -from chat import ChatTextEdit -from input import InputLineEdit -import weechat.color as color -QtCore = qt_compat.import_module('QtCore') -QtGui = qt_compat.import_module('QtGui') +from qweechat.chat import ChatTextEdit +from qweechat.input import InputLineEdit +from qweechat.weechat import color + +from PySide6 import QtCore, QtGui, QtWidgets -class GenericListWidget(QtGui.QListWidget): +class GenericListWidget(QtWidgets.QListWidget): """Generic QListWidget with dynamic size.""" def __init__(self, *args): - QtGui.QListWidget.__init__(*(self,) + args) + super().__init__(*args) self.setMaximumWidth(100) self.setTextElideMode(QtCore.Qt.ElideNone) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) @@ -52,17 +50,17 @@ class GenericListWidget(QtGui.QListWidget): def clear(self, *args): """Re-implement clear to set dynamic size after clear.""" - QtGui.QListWidget.clear(*(self,) + args) + QtWidgets.QListWidget.clear(*(self,) + args) self.auto_resize() def addItem(self, *args): """Re-implement addItem to set dynamic size after add.""" - QtGui.QListWidget.addItem(*(self,) + args) + QtWidgets.QListWidget.addItem(*(self,) + args) self.auto_resize() def insertItem(self, *args): """Re-implement insertItem to set dynamic size after insert.""" - QtGui.QListWidget.insertItem(*(self,) + args) + QtWidgets.QListWidget.insertItem(*(self,) + args) self.auto_resize() @@ -70,7 +68,7 @@ class BufferListWidget(GenericListWidget): """Widget with list of buffers.""" def __init__(self, *args): - GenericListWidget.__init__(*(self,) + args) + super().__init__(*args) def switch_prev_buffer(self): if self.currentRow() > 0: @@ -85,23 +83,23 @@ class BufferListWidget(GenericListWidget): self.setCurrentRow(0) -class BufferWidget(QtGui.QWidget): +class BufferWidget(QtWidgets.QWidget): """ Widget with (from top to bottom): title, chat + nicklist (optional) + prompt/input. """ def __init__(self, display_nicklist=False): - QtGui.QWidget.__init__(self) + super().__init__() # title - self.title = QtGui.QLineEdit() + self.title = QtWidgets.QLineEdit() self.title.setFocusPolicy(QtCore.Qt.NoFocus) # splitter with chat + nicklist - self.chat_nicklist = QtGui.QSplitter() - self.chat_nicklist.setSizePolicy(QtGui.QSizePolicy.Expanding, - QtGui.QSizePolicy.Expanding) + self.chat_nicklist = QtWidgets.QSplitter() + self.chat_nicklist.setSizePolicy(QtWidgets.QSizePolicy.Expanding, + QtWidgets.QSizePolicy.Expanding) self.chat = ChatTextEdit(debug=False) self.chat_nicklist.addWidget(self.chat) self.nicklist = GenericListWidget() @@ -110,16 +108,16 @@ class BufferWidget(QtGui.QWidget): self.chat_nicklist.addWidget(self.nicklist) # prompt + input - self.hbox_edit = QtGui.QHBoxLayout() + self.hbox_edit = QtWidgets.QHBoxLayout() self.hbox_edit.setContentsMargins(0, 0, 0, 0) self.hbox_edit.setSpacing(0) self.input = InputLineEdit(self.chat) self.hbox_edit.addWidget(self.input) - prompt_input = QtGui.QWidget() + prompt_input = QtWidgets.QWidget() prompt_input.setLayout(self.hbox_edit) # vbox with title + chat/nicklist + prompt/input - vbox = QtGui.QVBoxLayout() + vbox = QtWidgets.QVBoxLayout() vbox.setContentsMargins(0, 0, 0, 0) vbox.setSpacing(0) vbox.addWidget(self.title) @@ -139,7 +137,7 @@ class BufferWidget(QtGui.QWidget): if self.hbox_edit.count() > 1: self.hbox_edit.takeAt(0) if prompt is not None: - label = QtGui.QLabel(prompt) + label = QtWidgets.QLabel(prompt) label.setContentsMargins(0, 0, 5, 0) self.hbox_edit.insertWidget(0, label) @@ -147,7 +145,7 @@ class BufferWidget(QtGui.QWidget): class Buffer(QtCore.QObject): """A WeeChat buffer.""" - bufferInput = qt_compat.Signal(str, str) + bufferInput = QtCore.Signal(str, str) def __init__(self, data={}): QtCore.QObject.__init__(self) @@ -167,15 +165,17 @@ class Buffer(QtCore.QObject): """Update title.""" try: self.widget.set_title( - color.remove(self.data['title'].decode('utf-8'))) - except: # noqa: E722 + color.remove(self.data['title'])) + except Exception: # noqa: E722 + # TODO: Debug print the exception to be fixed. + # traceback.print_exc() self.widget.set_title(None) def update_prompt(self): """Update prompt.""" try: self.widget.set_prompt(self.data['local_variables']['nick']) - except: # noqa: E722 + except Exception: # noqa: E722 self.widget.set_prompt(None) def input_text_sent(self, text): @@ -243,6 +243,6 @@ class Buffer(QtCore.QObject): pixmap = QtGui.QPixmap(8, 8) pixmap.fill() icon = QtGui.QIcon(pixmap) - item = QtGui.QListWidgetItem(icon, nick['name']) + item = QtWidgets.QListWidgetItem(icon, nick['name']) self.widget.nicklist.addItem(item) self.widget.nicklist.setVisible(True) diff --git a/qweechat/chat.py b/qweechat/chat.py index b8cf8d5..2d5f47e 100644 --- a/qweechat/chat.py +++ b/qweechat/chat.py @@ -21,19 +21,18 @@ # import datetime -import qt_compat -import config -import weechat.color as color +from qweechat import config +from qweechat.weechat import color -QtCore = qt_compat.import_module('QtCore') -QtGui = qt_compat.import_module('QtGui') +from PySide6 import QtCore +from PySide6 import QtWidgets, QtGui -class ChatTextEdit(QtGui.QTextEdit): +class ChatTextEdit(QtWidgets.QTextEdit): """Chat area.""" def __init__(self, debug, *args): - QtGui.QTextEdit.__init__(*(self,) + args) + QtWidgets.QTextEdit.__init__(*(self,) + args) self.debug = debug self.readOnly = True self.setFocusPolicy(QtCore.Qt.NoFocus) @@ -77,9 +76,9 @@ class ChatTextEdit(QtGui.QTextEdit): prefix = '\x01(F%s)%s' % (forcecolor, prefix) text = '\x01(F%s)%s' % (forcecolor, text) if prefix: - self._display_with_colors(str(prefix).decode('utf-8') + ' ') + self._display_with_colors(prefix + ' ') if text: - self._display_with_colors(str(text).decode('utf-8')) + self._display_with_colors(text) if text[-1:] != '\n': self.insertPlainText('\n') else: diff --git a/qweechat/config.py b/qweechat/config.py index 1613860..8fcc901 100644 --- a/qweechat/config.py +++ b/qweechat/config.py @@ -20,7 +20,7 @@ # along with QWeeChat. If not, see . # -import ConfigParser +import configparser import os CONFIG_DIR = '%s/.qweechat' % os.getenv('HOME') @@ -91,7 +91,7 @@ config_color_options = [] def read(): """Read config file.""" global config_color_options - config = ConfigParser.RawConfigParser() + config = configparser.RawConfigParser() if os.path.isfile(CONFIG_FILENAME): config.read(CONFIG_FILENAME) @@ -123,7 +123,7 @@ def write(config): """Write config file.""" if not os.path.exists(CONFIG_DIR): os.mkdir(CONFIG_DIR, 0o0755) - with open(CONFIG_FILENAME, 'wb') as cfg: + with open(CONFIG_FILENAME, 'w') as cfg: config.write(cfg) diff --git a/qweechat/connection.py b/qweechat/connection.py index 8a0ee71..c1107f2 100644 --- a/qweechat/connection.py +++ b/qweechat/connection.py @@ -20,29 +20,27 @@ # along with QWeeChat. If not, see . # -import qt_compat +from PySide6 import QtGui, QtWidgets -QtGui = qt_compat.import_module('QtGui') - -class ConnectionDialog(QtGui.QDialog): +class ConnectionDialog(QtWidgets.QDialog): """Connection window.""" def __init__(self, values, *args): - QtGui.QDialog.__init__(*(self,) + args) + super().__init__(*args) self.values = values self.setModal(True) - grid = QtGui.QGridLayout() + grid = QtWidgets.QGridLayout() grid.setSpacing(10) self.fields = {} for line, field in enumerate(('server', 'port', 'password', 'lines')): - grid.addWidget(QtGui.QLabel(field.capitalize()), line, 0) - line_edit = QtGui.QLineEdit() + grid.addWidget(QtWidgets.QLabel(field.capitalize()), line, 0) + line_edit = QtWidgets.QLineEdit() line_edit.setFixedWidth(200) if field == 'password': - line_edit.setEchoMode(QtGui.QLineEdit.Password) + line_edit.setEchoMode(QtWidgets.QLineEdit.Password) if field == 'lines': validator = QtGui.QIntValidator(0, 2147483647, self) line_edit.setValidator(validator) @@ -51,14 +49,14 @@ class ConnectionDialog(QtGui.QDialog): grid.addWidget(line_edit, line, 1) self.fields[field] = line_edit if field == 'port': - ssl = QtGui.QCheckBox('SSL') + ssl = QtWidgets.QCheckBox('SSL') ssl.setChecked(self.values['ssl'] == 'on') grid.addWidget(ssl, line, 2) self.fields['ssl'] = ssl - self.dialog_buttons = QtGui.QDialogButtonBox() + self.dialog_buttons = QtWidgets.QDialogButtonBox() self.dialog_buttons.setStandardButtons( - QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel) + QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel) self.dialog_buttons.rejected.connect(self.close) grid.addWidget(self.dialog_buttons, 4, 0, 1, 2) diff --git a/qweechat/debug.py b/qweechat/debug.py index 3dd37d5..b5f4d85 100644 --- a/qweechat/debug.py +++ b/qweechat/debug.py @@ -20,25 +20,24 @@ # along with QWeeChat. If not, see . # -import qt_compat -from chat import ChatTextEdit -from input import InputLineEdit +from qweechat.chat import ChatTextEdit +from qweechat.input import InputLineEdit -QtGui = qt_compat.import_module('QtGui') +from PySide6 import QtWidgets -class DebugDialog(QtGui.QDialog): +class DebugDialog(QtWidgets.QDialog): """Debug dialog.""" def __init__(self, *args): - QtGui.QDialog.__init__(*(self,) + args) + QtWidgets.QDialog.__init__(*(self,) + args) self.resize(640, 480) self.setWindowTitle('Debug console') self.chat = ChatTextEdit(debug=True) self.input = InputLineEdit(self.chat) - vbox = QtGui.QVBoxLayout() + vbox = QtWidgets.QVBoxLayout() vbox.addWidget(self.chat) vbox.addWidget(self.input) diff --git a/qweechat/input.py b/qweechat/input.py index 5bde922..9d81c1f 100644 --- a/qweechat/input.py +++ b/qweechat/input.py @@ -20,21 +20,19 @@ # along with QWeeChat. If not, see . # -import qt_compat +from PySide6 import QtCore +from PySide6 import QtWidgets -QtCore = qt_compat.import_module('QtCore') -QtGui = qt_compat.import_module('QtGui') - -class InputLineEdit(QtGui.QLineEdit): +class InputLineEdit(QtWidgets.QLineEdit): """Input line.""" - bufferSwitchPrev = qt_compat.Signal() - bufferSwitchNext = qt_compat.Signal() - textSent = qt_compat.Signal(str) + bufferSwitchPrev = QtCore.Signal() + bufferSwitchNext = QtCore.Signal() + textSent = QtCore.Signal(str) def __init__(self, scroll_widget): - QtGui.QLineEdit.__init__(self) + super().__init__() self.scroll_widget = scroll_widget self._history = [] self._history_index = -1 @@ -50,7 +48,7 @@ class InputLineEdit(QtGui.QLineEdit): elif key == QtCore.Qt.Key_PageDown: self.bufferSwitchNext.emit() else: - QtGui.QLineEdit.keyPressEvent(self, event) + QtWidgets.QLineEdit.keyPressEvent(self, event) elif modifiers == QtCore.Qt.AltModifier: if key in (QtCore.Qt.Key_Left, QtCore.Qt.Key_Up): self.bufferSwitchPrev.emit() @@ -65,7 +63,7 @@ class InputLineEdit(QtGui.QLineEdit): elif key == QtCore.Qt.Key_End: bar.setValue(bar.maximum()) else: - QtGui.QLineEdit.keyPressEvent(self, event) + QtWidgets.QLineEdit.keyPressEvent(self, event) elif key == QtCore.Qt.Key_PageUp: bar.setValue(bar.value() - bar.pageStep()) elif key == QtCore.Qt.Key_PageDown: @@ -75,10 +73,10 @@ class InputLineEdit(QtGui.QLineEdit): elif key == QtCore.Qt.Key_Down: self._history_navigate(1) else: - QtGui.QLineEdit.keyPressEvent(self, event) + QtWidgets.QLineEdit.keyPressEvent(self, event) def _input_return_pressed(self): - self._history.append(self.text().encode('utf-8')) + self._history.append(self.text()) self._history_index = len(self._history) self.textSent.emit(self.text()) self.clear() diff --git a/qweechat/network.py b/qweechat/network.py index 8c497ea..889c424 100644 --- a/qweechat/network.py +++ b/qweechat/network.py @@ -21,11 +21,11 @@ # import struct -import qt_compat -import config -QtCore = qt_compat.import_module('QtCore') -QtNetwork = qt_compat.import_module('QtNetwork') +from PySide6 import QtCore, QtNetwork + +from qweechat import config + _PROTO_INIT_CMD = ['init password=%(password)s'] @@ -47,11 +47,11 @@ _PROTO_SYNC_CMDS = [ class Network(QtCore.QObject): """I/O with WeeChat/relay.""" - statusChanged = qt_compat.Signal(str, str) - messageFromWeechat = qt_compat.Signal(QtCore.QByteArray) + statusChanged = QtCore.Signal(str, str) + messageFromWeechat = QtCore.Signal(QtCore.QByteArray) def __init__(self, *args): - QtCore.QObject.__init__(*(self,) + args) + super().__init__(*args) self.status_disconnected = 'disconnected' self.status_connecting = 'connecting...' self.status_connected = 'connected' @@ -63,7 +63,7 @@ class Network(QtCore.QObject): self._buffer = QtCore.QByteArray() self._socket = QtNetwork.QSslSocket() self._socket.connected.connect(self._socket_connected) - self._socket.error.connect(self._socket_error) + # self._socket.error.connect(self._socket_error) self._socket.readyRead.connect(self._socket_read) self._socket.disconnected.connect(self._socket_disconnected) @@ -87,7 +87,7 @@ class Network(QtCore.QObject): self._buffer.append(data) while len(self._buffer) >= 4: remainder = None - length = struct.unpack('>i', self._buffer[0:4])[0] + length = struct.unpack('>i', self._buffer[0:4].data())[0] if len(self._buffer) < length: # partial message, just wait for end of message break @@ -108,7 +108,7 @@ class Network(QtCore.QObject): self._server = None self._port = None self._ssl = None - self._password = None + self._password = "" self.statusChanged.emit(self.status_disconnected, None) def is_connected(self): @@ -136,11 +136,12 @@ class Network(QtCore.QObject): return if self._socket.state() != QtNetwork.QAbstractSocket.UnconnectedState: self._socket.abort() - self._socket.connectToHost(self._server, self._port) if self._ssl: self._socket.ignoreSslErrors() - self._socket.startClientEncryption() - self.statusChanged.emit(self.status_connecting, None) + self._socket.connectToHostEncrypted(self._server, self._port) + else: + self._socket.connectToHost(self._server, self._port) + self.statusChanged.emit(self.status_connecting, "") def disconnect_weechat(self): """Disconnect from WeeChat.""" diff --git a/qweechat/qt_compat.py b/qweechat/qt_compat.py deleted file mode 100644 index 8940288..0000000 --- a/qweechat/qt_compat.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- coding: utf-8 -*- -# -# File downloaded from: -# https://github.com/epage/PythonUtils/blob/master/util/qt_compat.py -# Author: epage -# License: LGPL 2.1 -# - -from __future__ import with_statement -from __future__ import division - -_TRY_PYSIDE = True -uses_pyside = False - -try: - if not _TRY_PYSIDE: - raise ImportError() - import PySide.QtCore as _QtCore - QtCore = _QtCore - uses_pyside = True -except ImportError: - import sip - sip.setapi('QString', 2) - sip.setapi('QVariant', 2) - import PyQt4.QtCore as _QtCore - QtCore = _QtCore - uses_pyside = False - - -def _pyside_import_module(moduleName): - pyside = __import__('PySide', globals(), locals(), [moduleName], -1) - return getattr(pyside, moduleName) - - -def _pyqt4_import_module(moduleName): - pyside = __import__('PyQt4', globals(), locals(), [moduleName], -1) - return getattr(pyside, moduleName) - - -if uses_pyside: - import_module = _pyside_import_module - - Signal = QtCore.Signal - Slot = QtCore.Slot - Property = QtCore.Property -else: - import_module = _pyqt4_import_module - - Signal = QtCore.pyqtSignal - Slot = QtCore.pyqtSlot - Property = QtCore.pyqtProperty - - -if __name__ == "__main__": - pass diff --git a/qweechat/qweechat.py b/qweechat/qweechat.py index 49e6b91..cc181c3 100644 --- a/qweechat/qweechat.py +++ b/qweechat/qweechat.py @@ -36,18 +36,18 @@ It requires requires WeeChat 0.3.7 or newer, running on local or remote host. import sys import traceback from pkg_resources import resource_filename -import qt_compat -import config -import weechat.protocol as protocol -from network import Network -from connection import ConnectionDialog -from buffer import BufferListWidget, Buffer -from debug import DebugDialog -from about import AboutDialog -from version import qweechat_version - -QtCore = qt_compat.import_module('QtCore') -QtGui = qt_compat.import_module('QtGui') + +from PySide6 import QtGui, QtWidgets, QtCore + +from qweechat import config +from qweechat.weechat import protocol +from qweechat.network import Network +from qweechat.connection import ConnectionDialog +from qweechat.buffer import BufferListWidget, Buffer +from qweechat.debug import DebugDialog +from qweechat.about import AboutDialog +from qweechat.version import qweechat_version + NAME = 'QWeeChat' AUTHOR = 'Sébastien Helleu' @@ -58,11 +58,11 @@ WEECHAT_SITE = 'https://weechat.org/' DEBUG_NUM_LINES = 50 -class MainWindow(QtGui.QMainWindow): +class MainWindow(QtWidgets.QMainWindow): """Main window.""" def __init__(self, *args): - QtGui.QMainWindow.__init__(*(self,) + args) + super().__init__() self.config = config.read() @@ -87,11 +87,11 @@ class MainWindow(QtGui.QMainWindow): # default buffer self.buffers = [Buffer()] - self.stacked_buffers = QtGui.QStackedWidget() + self.stacked_buffers = QtWidgets.QStackedWidget() self.stacked_buffers.addWidget(self.buffers[0].widget) # splitter with buffers + chat/input - splitter = QtGui.QSplitter() + splitter = QtWidgets.QSplitter() splitter.addWidget(self.list_buffers) splitter.addWidget(self.stacked_buffers) @@ -146,7 +146,7 @@ class MainWindow(QtGui.QMainWindow): menu_window.addAction(self.actions['debug']) menu_help = self.menu.addMenu('&Help') menu_help.addAction(self.actions['about']) - self.network_status = QtGui.QLabel() + self.network_status = QtWidgets.QLabel() self.network_status.setFixedHeight(20) self.network_status.setFixedWidth(200) self.network_status.setContentsMargins(0, 0, 10, 0) @@ -249,8 +249,7 @@ class MainWindow(QtGui.QMainWindow): '© 2011-2020 %s <%s>' % (AUTHOR, AUTHOR_MAIL, AUTHOR_MAIL), '', - 'Running with %s' % ('PySide' if qt_compat.uses_pyside - else 'PyQt4'), + 'Running with PySide6', '', 'WeeChat site: %s' % (WEECHAT_SITE, WEECHAT_SITE), @@ -315,11 +314,11 @@ class MainWindow(QtGui.QMainWindow): self.debug_display(0, '==>', 'message (%d bytes):\n%s' % (len(message), - protocol.hex_and_ascii(message, 20)), + protocol.hex_and_ascii(message.data(), 20)), forcecolor='#008800') try: proto = protocol.Protocol() - message = proto.decode(str(message)) + message = proto.decode(message.data()) if message.uncompressed: self.debug_display( 0, '==>', @@ -329,7 +328,7 @@ class MainWindow(QtGui.QMainWindow): forcecolor='#008800') self.debug_display(0, '', 'Message: %s' % message) self.parse_message(message) - except: # noqa: E722 + except Exception: # noqa: E722 print('Error while decoding message from WeeChat:\n%s' % traceback.format_exc()) self.network.disconnect_weechat() @@ -495,6 +494,8 @@ class MainWindow(QtGui.QMainWindow): self.network.desync_weechat() elif message.msgid == '_upgrade_ended': self.network.sync_weechat() + else: + print(f"Unknown message with id {message.msgid}") def create_buffer(self, item): """Create a new buffer.""" @@ -509,9 +510,8 @@ class MainWindow(QtGui.QMainWindow): def insert_buffer(self, index, buf): """Insert a buffer in list.""" self.buffers.insert(index, buf) - self.list_buffers.insertItem(index, '%d. %s' - % (buf.data['number'], - buf.data['full_name'].decode('utf-8'))) + self.list_buffers.insertItem(index, '%s' + % (buf.data['local_variables']['name'])) self.stacked_buffers.insertWidget(index, buf.widget) def remove_buffer(self, index): @@ -544,12 +544,18 @@ class MainWindow(QtGui.QMainWindow): if self.debug_dialog: self.debug_dialog.close() config.write(self.config) - QtGui.QMainWindow.closeEvent(self, event) + QtWidgets.QMainWindow.closeEvent(self, event) + + +def main(): + app = QtWidgets.QApplication(sys.argv) + app.setStyle(QtWidgets.QStyleFactory.create('Cleanlooks')) + app.setWindowIcon(QtGui.QIcon( + resource_filename(__name__, 'data/icons/weechat.png'))) + main = MainWindow() + main.show() + sys.exit(app.exec_()) -app = QtGui.QApplication(sys.argv) -app.setStyle(QtGui.QStyleFactory.create('Cleanlooks')) -app.setWindowIcon(QtGui.QIcon( - resource_filename(__name__, 'data/icons/weechat.png'))) -main = MainWindow() -sys.exit(app.exec_()) +if __name__ == '__main__': + main() diff --git a/qweechat/weechat/color.py b/qweechat/weechat/color.py index d732006..b11bffc 100644 --- a/qweechat/weechat/color.py +++ b/qweechat/weechat/color.py @@ -21,6 +21,7 @@ # import re +import logging RE_COLOR_ATTRS = r'[*!/_|]*' RE_COLOR_STD = r'(?:%s\d{2})' % RE_COLOR_ATTRS @@ -75,6 +76,9 @@ WEECHAT_BASIC_COLORS = ( ('white', 0)) +log = logging.getLogger(__name__) + + class Color(): def __init__(self, color_options, debug=False): self.color_options = color_options @@ -92,7 +96,7 @@ class Color(): index = int(color) return '\x01(Fr%s)' % self.color_options[index] except: # noqa: E722 - print('Error decoding WeeChat color "%s"' % color) + log.debug('Error decoding WeeChat color "%s"' % color) return '' def _convert_terminal_color(self, fg_bg, attrs, color): @@ -100,7 +104,7 @@ class Color(): index = int(color) return '\x01(%s%s#%s)' % (fg_bg, attrs, self._rgb_color(index)) except: # noqa: E722 - print('Error decoding terminal color "%s"' % color) + log.debug('Error decoding terminal color "%s"' % color) return '' def _convert_color_attr(self, fg_bg, color): @@ -123,7 +127,7 @@ class Color(): return self._convert_terminal_color(fg_bg, attrs, WEECHAT_BASIC_COLORS[index][1]) except: # noqa: E722 - print('Error decoding color "%s"' % color) + log.debug('Error decoding color "%s"' % color) return '' def _attrcode_to_char(self, code): diff --git a/qweechat/weechat/protocol.py b/qweechat/weechat/protocol.py index 79b24c1..4e1514d 100644 --- a/qweechat/weechat/protocol.py +++ b/qweechat/weechat/protocol.py @@ -34,15 +34,11 @@ import collections import struct import zlib -if hasattr(collections, 'OrderedDict'): - # python >= 2.7 - class WeechatDict(collections.OrderedDict): - def __str__(self): - return '{%s}' % ', '.join( - ['%s: %s' % (repr(key), repr(self[key])) for key in self]) -else: - # python <= 2.6 - WeechatDict = dict + +class WeechatDict(collections.OrderedDict): + def __str__(self): + return '{%s}' % ', '.join( + ['%s: %s' % (repr(key), repr(self[key])) for key in self]) class WeechatObject: @@ -151,7 +147,7 @@ class Protocol: if len(self.data) < 3: self.data = '' return '' - objtype = str(self.data[0:3]) + objtype = self.data[0:3].decode() self.data = self.data[3:] return objtype @@ -196,14 +192,14 @@ class Protocol: value = self._obj_len_data(1) if value is None: return None - return int(str(value)) + return int(value) def _obj_str(self): """Read a string in data (length on 4 bytes + content).""" value = self._obj_len_data(4) - if value is None: - return None - return str(value) + if value in ("", None): + return "" + return value.decode() def _obj_buffer(self): """Read a buffer in data (length on 4 bytes + data).""" @@ -214,14 +210,14 @@ class Protocol: value = self._obj_len_data(1) if value is None: return None - return '0x%s' % str(value) + return '0x%s' % value def _obj_time(self): """Read a time in data (length on 1 byte + value as string).""" value = self._obj_len_data(1) if value is None: return None - return int(str(value)) + return int(value) def _obj_hashtable(self): """ @@ -314,8 +310,8 @@ class Protocol: if compression: uncompressed = zlib.decompress(self.data[5:]) size_uncompressed = len(uncompressed) + 5 - uncompressed = '%s%s%s' % (struct.pack('>i', size_uncompressed), - struct.pack('b', 0), uncompressed) + uncompressed = b'%s%s%s' % (struct.pack('>i', size_uncompressed), + struct.pack('b', 0), uncompressed) self.data = uncompressed else: uncompressed = self.data[:] @@ -344,13 +340,20 @@ def hex_and_ascii(data, bytes_per_line=10): for i in range(num_lines): str_hex = [] str_ascii = [] - for char in data[i*bytes_per_line:(i*bytes_per_line)+bytes_per_line]: + for j in range(bytes_per_line): + # We can't easily iterate over individual bytes, so we are going to + # do it this way. + index = (i*bytes_per_line) + j + char = data[index:index+1] + if not char: + char = b'x' byte = struct.unpack('B', char)[0] - str_hex.append('%02X' % int(byte)) + str_hex.append(b'%02X' % int(byte)) if byte >= 32 and byte <= 127: str_ascii.append(char) else: - str_ascii.append('.') - fmt = '%%-%ds %%s' % ((bytes_per_line * 3) - 1) - lines.append(fmt % (' '.join(str_hex), ''.join(str_ascii))) - return '\n'.join(lines) + str_ascii.append(b'.') + fmt = b'%%-%ds %%s' % ((bytes_per_line * 3) - 1) + lines.append(fmt % (b' '.join(str_hex), + b''.join(str_ascii))) + return b'\n'.join(lines) diff --git a/qweechat/weechat/testproto.py b/qweechat/weechat/testproto.py index c90d538..76a7aed 100644 --- a/qweechat/weechat/testproto.py +++ b/qweechat/weechat/testproto.py @@ -24,8 +24,6 @@ Command-line program for testing WeeChat/relay protocol. """ -from __future__ import print_function - import argparse import os import select @@ -36,8 +34,9 @@ import sys import time import traceback -import protocol # WeeChat/relay protocol -from .. version import qweechat_version +from qweechat.weechat import protocol + +qweechat_version = '0.1' NAME = 'qweechat-testproto' @@ -61,12 +60,13 @@ class TestProto(object): try: self.sock = socket.socket(inet, socket.SOCK_STREAM) self.sock.connect((self.args.hostname, self.args.port)) - except: # noqa: E722 + except Exception: if self.sock: self.sock.close() print('Failed to connect to', self.address) return False - print('Connected to', self.address) + + print(f'Connected to {self.address} socket {self.sock}') return True def send(self, messages): @@ -75,11 +75,12 @@ class TestProto(object): Return True if OK, False if error. """ try: - for msg in messages.split('\n'): - if msg == 'quit': + for msg in messages.split(b'\n'): + if msg == b'quit': self.has_quit = True - self.sock.sendall(msg + '\n') - print('\x1b[33m<-- ' + msg + '\x1b[0m') + self.sock.sendall(msg + b'\n') + sys.stdout.write( + (b'\x1b[33m<-- ' + msg + b'\x1b[0m\n').decode()) except: # noqa: E722 traceback.print_exc() print('Failed to send message') @@ -94,7 +95,7 @@ class TestProto(object): try: proto = protocol.Protocol() msgd = proto.decode(message, - separator='\n' if self.args.debug > 0 + separator=b'\n' if self.args.debug > 0 else ', ') print('') if self.args.debug >= 2 and msgd.uncompressed: @@ -122,7 +123,7 @@ class TestProto(object): data = os.read(sys.stdin.fileno(), 4096) if data: if not self.send(data.strip()): - # self.sock.close() + self.sock.close() return False # open stdin to read user commands sys.stdin = open('/dev/tty') @@ -136,10 +137,10 @@ class TestProto(object): """ if self.has_quit: return 0 - message = '' - recvbuf = '' - prompt = '\x1b[36mrelay> \x1b[0m' - sys.stdout.write(prompt) + message = b'' + recvbuf = b'' + prompt = b'\x1b[36mrelay> \x1b[0m' + sys.stdout.write(prompt.decode()) sys.stdout.flush() try: while not self.has_quit: @@ -149,13 +150,14 @@ class TestProto(object): buf = os.read(_file.fileno(), 4096) if buf: message += buf - if '\n' in message: - messages = message.split('\n') - msgsent = '\n'.join(messages[:-1]) + if b'\n' in message: + messages = message.split(b'\n') + msgsent = b'\n'.join(messages[:-1]) if msgsent and not self.send(msgsent): return 4 message = messages[-1] - sys.stdout.write(prompt + message) + sys.stdout.write((prompt + message).decode()) + # sys.stdout.write(prompt + message) sys.stdout.flush() else: buf = _file.recv(4096) @@ -178,12 +180,12 @@ class TestProto(object): if remainder: recvbuf = remainder else: - recvbuf = '' - sys.stdout.write(prompt + message) + recvbuf = b'' + sys.stdout.write((prompt + message).decode()) sys.stdout.flush() except: # noqa: E722 traceback.print_exc() - self.send('quit') + self.send(b'quit') return 0 def __del__(self): @@ -220,7 +222,7 @@ The script returns: help='debug mode: long objects view ' '(-dd: display raw messages)') parser.add_argument('-v', '--version', action='version', - version=qweechat_version()) + version=qweechat_version) parser.add_argument('hostname', help='hostname (or IP address) of machine running ' 'WeeChat/relay') diff --git a/setup.py b/setup.py index c6edcbe..d22cf9f 100644 --- a/setup.py +++ b/setup.py @@ -54,5 +54,8 @@ setup( 'console_scripts': [ 'qweechat-testproto = qweechat.weechat.testproto:main', ] - } + }, + install_requires = [ + 'PySide6', + ] )